git remove merge commit from history

216,779

Solution 1

Do git rebase -i <sha before the branches diverged> this will allow you to remove the merge commit and the log will be one single line as you wanted. You can also delete any commits that you do not want any more. The reason that your rebase wasn't working was that you weren't going back far enough.

WARNING: You are rewriting history doing this. Doing this with changes that have been pushed to a remote repo will cause issues. I recommend only doing this with commits that are local.

Solution 2

Starting with the repo in the original state

Original repo history

To remove the merge commit and squash the branch into a single commit in the mainline

Squashed commits, no merge commit

Use these commands (replacing 5 and 1 with the SHAs of the corresponding commits):

git checkout 5
git reset --soft 1
git commit --amend -m '1 2 3 4 5'
git rebase HEAD master

To retain a merge commit but squash the branch commits into one:

Squashed commits, retained merge commit

Use these commands (replacing 5, 1 and C with the SHAs of the corresponding commits):

git checkout -b tempbranch 5
git reset --soft 1
git commit --amend -m '1 2 3 4 5'
git checkout C
git merge --no-ff tempbranch
git rebase HEAD master

To remove the merge commit and replace it with individual commits from the branch

Branch moved into mainline, no merge commit

Just do (replacing 5 with the SHA of the corresponding commit):

git rebase 5 master

And finally, to remove the branch entirely

Branch removed entirely

Use this command (replacing C and D with the SHAs of the corresponding commits):

git rebase --onto C D~ master

Solution 3

To Just Remove a Merge Commit

If all you want to do is to remove a merge commit (2) so that it is like it never happened, the command is simply as follows

git rebase --onto <sha of 1> <sha of 2> <blue branch>

And now the purple branch isn't in the commit log of blue at all and you have two separate branches again. You can then squash the purple independently and do whatever other manipulations you want without the merge commit in the way.

Solution 4

There are two ways to tackle this based on what you want:

Solution 1: Remove purple commits, preserving history (incase you want to roll back)

git revert -m 1 <SHA of merge>

-m 1 specifies which parent line to choose

Purple commits will still be there in history but since you have reverted, you will not see code from those commits.


Solution 2: Completely remove purple commits (disruptive change if repo is shared)

git rebase -i <SHA before branching out>

and delete (remove lines) corresponding to purple commits.

This would be less tricky if commits were not made after merge. Additional commits increase the chance of conflicts during revert/rebase.

Solution 5

For full control over the operation and to preserve any merge commits you want to keep along the way, the modern approach is to use

git rebase -i -r

Share:
216,779
Benjamin Toueg
Author by

Benjamin Toueg

Updated on April 29, 2021

Comments

  • Benjamin Toueg
    Benjamin Toueg about 3 years

    My Git history looks like that :

    Git history

    I would like to squash the purple commits into a single one. I don't want to see them ever again in my commit log.

    I've tried to do a git rebase -i 1, but even though 1 is on the blue branch (cf. picture), I still see every commit on my purple branch.

    How can I completely remove the purple branch (from commit log) ?

  • Benjamin Toueg
    Benjamin Toueg almost 11 years
    Even if I choose a sha before the branches have diverged, I see all the commits of the purple branch -_-
  • Schleis
    Schleis almost 11 years
    Yeah, then you delete them in the editor that comes up with git rebase and they will be removed.
  • Benjamin Toueg
    Benjamin Toueg almost 11 years
    Deleting the commits resulted in losing all the modification of the merge. But I did a soft reset and I've been able to have something quite like I wanted (order do not match initial expectations).
  • Admin
    Admin almost 11 years
    This does not sound right. Leaving aside the fact that it's hard to tell what the original poster wanted to do with the purple commits in the first place, if you revert the merge, that's fine, that will do a reverse patch of the changes from that commit and add it as another commit, canceling the purple commits out. It's like 1 - 1 = 0. But if you then rebase out the purple commits, you leave behind the reverted patch, unless you rebase that out too. If you don't, it's like applying -1 to your history, not 0, so you'll leave behind changes you don't want.
  • prem
    prem almost 11 years
    @Cupcake, provided were two separate answers. I have revised answer to be less confusing :P
  • grgry
    grgry about 8 years
    this answer is incomplete in detail, which branch do yu initiate the rebase from?
  • Schleis
    Schleis about 8 years
    @gregorynich You are dealing with only one branch, it just has another branch merged in. Which results in all the commits showing up in the history, the OP's question doesn't talk about other branches.
  • thecoshman
    thecoshman over 6 years
    Fairly sure you do not want to 'remove' the commits. 'remove' is not an option in rebase, but delete is. if you delete a commit, you will loose the changes it introduced. You want to squash the commits.
  • thecoshman
    thecoshman over 6 years
    AFAIK this is not what the OP is asking for. He wants to keep the changes, but remove the noise from his log. For that, he needs to squash the commits down, deleting will remove the changes.
  • Cosmin Lehene
    Cosmin Lehene over 6 years
    Why does this rebase need to be interactive? I noticed it won't work otherwise, or I'm missing something.
  • Schleis
    Schleis over 6 years
    @CosminLehene if it isn't interactive, you won't be able to edit the list of commits
  • Roy
    Roy almost 6 years
    in git rebase 5 master case, why it is not "A B C 1 2 3 4 5 D ..." order?
  • Allen Luce
    Allen Luce almost 6 years
    That command takes the commits that master doesn't have in common with 5 and plops them on top of 5. The commit at C isn't part of the lineage of 5, it's the first to be moved on top of 5.
  • Allen Luce
    Allen Luce almost 6 years
    If you want to end up with "A B C 1 2 3 4 5 D ..." you can do: git rebase C 5; git rebase 5 master
  • Awi
    Awi about 5 years
    It worked for me. After rebase was complete; I had to do a git push -f origin develop
  • prem
    prem over 4 years
    True, looks like the original question has been rephrased. This answer is not for OPs problem.
  • Roshambo
    Roshambo almost 4 years
    Of all the answers, I find this both the most straightforward and the easiest to do. Thank you.
  • Tony
    Tony over 3 years
    This is the first step to the question, and I agree the easiest that does exactly what was requested. The second step would be git merge --squash <purple branch name>