6
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

4
  • 'Please Help.' Everytime I read this I got something going on in my throat... I flag this question as a duplicate: stackoverflow.com/questions/30136558/… Commented Dec 19, 2017 at 13:46
  • Possible duplicate of Git: How to squash commits which have merge-commit in between? Commented Dec 19, 2017 at 13:46
  • Clearly not a duplicate of "How to squash commits which have merge-commit in between", because this question is about how to squash with the merge commit itself. (To be clear: the same answer might work, but it's not the same question and someone searching for this isn't likely to find the other question and think it's the solution.) Commented Dec 19, 2017 at 14:44
  • I'd say "dont't", but maybe if you tell why do you need there is something else you should do Commented Dec 19, 2017 at 17:22

2 Answers 2

12

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 
Sign up to request clarification or add additional context in comments.

Comments

4

As the accepted answer says, git rebase -i (aka --interactive) supports an additional option -p (aka --preserve-merges). However, unlike the accepted answer, I wanted to point out that this actually seems to work fine to achieve exactly the desired result, so that if you do git rebase -i -p HEAD~2 the merge commit appears in the interactive rebase file:

pick abcdeff Merge branch 'feature' into develop pick abcdefc Extra changes 

Now you can edit this rebase file to mark the second commit for squashing and finish the rebase. It all seems to work fine.

However, I do not understand the intricacies of why the git documentation warns against using using -i -p (and in some, but not all, versions of the documentation says that -p is deprecated) so your mileage may vary. It seems that the main problems come when trying to re-order the commits displayed when using this... so don't do that!

The recommended alternative to the deprecated -p option seems to be git rebase -i -r; but that produces a very long and complex interactive rebase file which looks nothing at all like what I am expecting (i.e. the simple rebase file shown as text above).

If anybody can add an answer explaining in any detail whether and why git rebase -i -p is (or isn't) okay in this case, that would be very helpful.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.