Benjamin Toueg
Benjamin Toueg

Reputation: 10867

git remove merge commit from history

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) ?

Upvotes: 175

Views: 338061

Answers (5)

squall3d
squall3d

Reputation: 1767

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

From man git rebase of git version 2.44.2 about -r:

-r, --rebase-merges[=(rebase-cousins|no-rebase-cousins)], --no-rebase-merges
By default, a rebase will simply drop merge commits from the todo list, and put the rebased commits into a single, linear branch. With --rebase-merges, the rebase will instead try
to preserve the branching structure within the commits that are to be rebased, by recreating the merge commits. Any resolved merge conflicts or manual amendments in these merge
commits will have to be resolved/re-applied manually.  --no-rebase-merges can be used to countermand both the rebase.rebaseMerges config option and a previous --rebase-merges.

When rebasing merges, there are two modes: rebase-cousins and no-rebase-cousins. If the mode is not specified, it defaults to no-rebase-cousins. In no-rebase-cousins mode, commits
which do not have <upstream> as direct ancestor will keep their original branch point, i.e. commits that would be excluded by git-log(1)'s --ancestry-path option will keep their
original ancestry by default. In rebase-cousins mode, such commits are instead rebased onto <upstream> (or <onto>, if specified).

It is currently only possible to recreate the merge commits using the ort merge strategy; different merge strategies can be used only via explicit exec git merge -s <strategy>
[...]  commands.

See also REBASING MERGES and INCOMPATIBLE OPTIONS below.

Upvotes: 12

Allen Luce
Allen Luce

Reputation: 8389

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

Upvotes: 149

Warren
Warren

Reputation: 2044

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.

Upvotes: 55

prem
prem

Reputation: 416

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.

Upvotes: 27

Schleis
Schleis

Reputation: 43700

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.

Upvotes: 155

Related Questions