By default, rebase
tries to produce a linear history. Also, rebase assumes that all changes are represented in non-merge commits (which, with the exception of conflict resolutions or "evil merges", should be true).
With two caveats, you can convince rebase
to acknowledge merge commits by using the --preserve-merges
option. The caveats are:
1) rebase
still won't properly handle changes made in a merge. It will try to re-create merges using default strategy, and will let you re-resolve conflicts if necessary. If the merge was created using --no-commit
in order to manually change things even though it wouldn't have conflicted, rebase
will silently change the result.
2) mixing --preserve-merges
with -i
is not generally safe. In specific cases it can be done, and this is one that could work if you're careful to limit what you're doing to just what needs done.
So you could try doing the rebase with --preserve-merges
and change nothing in the TODO list except for setting the command for D
to "reword".
This will replace commits D
and F
, so in the event other refs point to either of them you'll have to move those refs as well. But as nothing has been pushed, the rewrite shouldn't cause any other major headaches.
There are other ways to do the rewrite, so if --preserve-merges
doesn't work right for you (or if you just don't want to mess with it), you could use git filter-branch
instead, with --msg-filter
. This is harder to set up, though, as you need to write a script that will transform D
s message while passing any other commit's message through. See https://git-scm.com/docs/git-filter-branch
Or you can manually rebuild the history. For example if you know that D
and F
are non-conflicting default merges, you can say
git checkout myBranch
git reset --hard HEAD~2
git merge master^
# enter the new commit message for D
git merge master
# re-enter the commit message for E
If you're not sure that the commits were non-conflicting default merges, you could do something like
git checkout myBranch
git tag temp
git reset --hard HEAD~2
git merge --no-commit master^
rm -rf *
git checkout temp^ -- .
git add .
git commit -m"new commit message for D"
git merge --no-commit master
rm -rf *
git checkout temp -- .
git add .
git commit -m"commit message for F"