문제

Suppose I have a repository like this:

I --- C --- M    master
  \       /
   `- A -´       topic

where M is a merge commit incorporating topic into master.

Later I find a bug in C, so I make a commit fixing it on the master branch, on top of M:

I --- C --- M --- C1    master
  \       /
   `- A -´              topic

but ideally I would like the history to look like this:

I --- C --- C1 --- M    master
  \              /
   `- A --------´       topic

How can I rewrite the history so that C1 appears before the merge M?

I could remove M, apply the patch made by C1, and merge topic into master again, resolving all the conflicts again, but I'd like to avoid the effort, and I'd prefer to preserve the original commit information (author, date, etc.) if possible, which rules out doing git commit again. I hope it's possible with git rebase, but I failed, with either one or both of -p and -i.

도움이 되었습니까?

해결책 3

The best way I've found is:

git checkout -b tmp master^^
# Now tmp is on top of C

git cherry-pick master
# Now tmp is on top of C1', a copy of C1

git rebase -p tmp master
# Now master is on top of a merge commit from C1' and A

git branch -d tmp

I don't know why git rebase cannot do this all at once without git cherry-pick, but at least I know this works.

다른 팁

This can be done with a single rebase to move the commit (or any number of commits) and then redoing the merge from topic.

# Create some branches just for readability
git branch mergeCommit master^
git branch beforeMerge master^^

# Run the rebase
git rebase --onto beforeMerge mergeCommit master
# After the rebase master will have the replayed commits on top of C

# Redo the merge
git merge topic

With this rebase you can move more that one commit before the merge. You could read the rebase instruction in plan english as:

Grab the commits from mergeCommit to master and rebase them on top of beforeMerge.

The commit M in your 3rd graph is not the same as M in the 2nd, since it has different ancestry. Therefore you have to reset master back before M, or use rebase to do it.

First commit your fix and then use git rebase -i to move the new commit before M.

To avoid having to resolve conflicts again, make sure you have rerere.enabled set to get git to remember resolutions. You have to do this before you first resolve it though so it gets remembered. Rerere (reuse recorded resolutions) is a fantastic feature.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top