gitgithubmergecommitsquash

How to squash a merge commit with a normal commit?


commit b0e5db36ed68d4562275adeb08001b1316a4da52
Merge: ea38baa 8220bb1

commit ea38baa3f46a48722987b8dd3892d2b8d81c4d1a

In this case how do I squash these two commits

I am using

git rebase -i HEAD~2

but this doesn't work as it removes the Merge commit and that is not available for squashing


Solution

  • So two factors to consider here:

    First, in a few ways rebase doesn't always play nice with merge commits. I'll come back to that a couple times.

    Second, it's not entirely clear what result you're expecting. If right now you have something like

    x -- x -- M -- C <--(master)
     \       /
      A --- B
    

    are you trying to end up with

    x -- x -- ABC <--(master)
    

    or

    x -- x -- MC <--(master)
     \       /
      A --- B
    

    If you want the version with ABC, it's pretty simple. While M doesn't appear in the TODO list of a rebase, all of the commits that were brought into the mainline by M (i.e. A and B in this example) are. So just mark B and C for "squash". The only thing to remember is that this is a history rewrite, so if you have already pushed any refs that can reach A, B, M, or C then some clean-up may be needed (see the rebase docs under "recovering from upstream rebase").

    If you want the version with MC, then there are a lot of problems. Not that you can't get it, but I don't think you can get it by doing a rebase; and also, MC would be an "evil merge", which could cause problems with future rebase attempts as well (among other things).

    By default rebase tries to produce a linear history and won't produce merge commits. You can get it to produce merge commits with the --preserve-merges option, but this doesn't interact well with -i (and if you were to try to modify a merge by doing it, I anticipate several possible problems).

    If you're not worried about the problems of hiding changes in a merge commit, and really want to produce a commit like MC, then the way to do it is:

    First, move the master ref back to M while keeping the changes from C in the index.

    git checkout master
    git reset --soft HEAD^
    

    Then re-apply the changes directly to the merge commit

    git commit --amend