Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert merge into rebase without having to perform the merge again

I made a mistake: I should have used git pull --rebase, but I issued a simple git pull, merged everything and now have a merge commit at the HEAD of my branch.

I want to get rid of that merge commit and I thought I'd just issue a git rebase -i HEAD~3, move my last local commit to the top and squash the merge commit into it. Alas, the merge commit is not available for squashing. If I do this, I get into intermediate states where I need to do the merge again, which is a lot of work.

Is there a way out of this without having to perform the merge again? It seems it should be possible to use the merge commit in some way?

like image 460
Confusion Avatar asked Sep 29 '15 09:09

Confusion


People also ask

Is rebasing a replacement for merging?

While merging is definitely the easiest and most common way to integrate changes, it's not the only one: "Rebase" is an alternative means of integration.

Why you should not use rebase?

Rebasing can be dangerous! Rewriting history of shared branches is prone to team work breakage. This can be mitigated by doing the rebase/squash on a copy of the feature branch, but rebase carries the implication that competence and carefulness must be employed.


1 Answers

tl;dr

Even if you can include merge commits in a rebase, you can't squash merge commits. Git will let you know by saying:

Refusing to squash a merge: <SHA-1>

What you can do in order to keep the changes made during the merge is to convert the merge commit into a normal commit. At that point you can squash it like any other commit.

Assuming HEAD is pointing to the merge commit:

git reset --soft HEAD~1  # Keeps changes in the index git commit               # Create a new commit, this time not a merge commit git rebase -i HEAD~4     # Do an interactive rebase and squash the new commit 

Preserving merge commits during a rebase

In general, you can preserve merge commits when doing a rebase using git rebase -p.
However, its purpose is to replay the commits leading up to the merge. Any changes that are part of the merge commits themselves (e.g. conflict resolutions) aren't preserved.

Here's from the documentation:

-p
--preserve-merges
Recreate merge commits instead of flattening the history by replaying commits a merge commit introduces. Merge conflict resolutions or manual amendments to merge commits are not preserved.
This uses the --interactive machinery internally, but combining it with the --interactive option explicitly is generally not a good idea unless you know what you are doing (see BUGS below)

The bug the documentation is referring to is triggered by reordering commits.

like image 153
Enrico Campidoglio Avatar answered Oct 10 '22 15:10

Enrico Campidoglio