In Git when I have commits eg. A - B - C
and I want to edit the B
commit, I
- use
git rebase -i <A-commit-hash>
,
- in the list I write
edit
command in front of B
commit,
- git rebase stops right after
B
commit so I can fix anything I want using git commit --amend
,
- and then I continue using
git rebase --continue
.
As far as I know this is the best practice how to do this. With this method I can edit any commit in the past (as long as it hasn't been pushed to remote branch yet), and moreover with -p
flag I can even preserve the merges. This is just great.
My current problem is: I did a mistake (typo) on one line in a merge commit (while resolving a conflict when merging two branches).
I'd like to fix it but I don't know how to make git rebase
to stop at a merge commit. The git rebase -p -i <blah>
list ignores merge commits, so I cannot write edit
command in front of it and make the git rebase
stop there to let me edit it.
Any help please?
I just want to fix this line in the merge commit while preserving all the commits (and merges) after it.
Thanks.
Git does not make it easy to do interactive rebases when merges are involved. The -p
option uses the -i
mechanism internally, so mixing the two doesn't really work.
However, git rebase
is just an automated way to do lots of cherry-picks. You can replicate its behavior by manually cherry-picking to get a bit more control over the process. It's less convenient and more prone to human error, but possible.
This is the approach I suggest:
- use
git rebase
to get to the commit after the merge (the child of the merge)
- use
git reset --hard HEAD^
to manually get to the merge
- use
git commit --amend
to repair the merge
- use
git cherry-pick
to get back to the commit after the merge
- use
git rebase --continue
to finish
Here are the specific steps:
- Note the SHA1 ID of the merge commit you want to modify. For discussion, suppose it is
deadbeef
.
- Note the SHA1 ID of the commit right after the merge commit you want to modify (the merge commit's child). Suppose it is
facef00d
.
- Run
git rebase -i deadbeef
.
- Select
facef00d
for editing.
- When rebase returns you to a prompt to edit
facef00d
, run git reset --hard HEAD^
. You should now be at deadbeef
(git rev-parse HEAD
should print deadbeef
).
- Make your edits to fix the incorrect merge conflict and use
git add
to stage them.
- Run
git commit --amend
to fuse the staged fix with the bad merge commit. The result will now have a different SHA1 (not deadbeef
).
- Run
git cherry-pick facef00d
to apply the changes made by facef00d
to the fixed merge commit.
- Run
git rebase --continue
to finish.
May be easier to create a fixup commit 'D' then use 'git rebase -p -i <blah>
' to reorder 'D' right after 'B' and squash it into 'B'.
pick A
pick B <- merge commit to ammend
fixup D
pick C