Home > Net >  git: Clean git history and keep only merged commits in master
git: Clean git history and keep only merged commits in master

Time:11-15

In our git repo we have a policy to squash merge all the commits. Recently there was a policy update and some changes got merged with their local commits details into master. Is there a way I can rewrite the history to only keep the merged commit and remove all the local commits.

For instance,current history looks like as in

Figure1

but I want to convert it to

Figure2

I tried rebase -i -p HEAD~3 and picked only the merged commits. I squashed/fixedup all the other local commits, but it failed.

Thanks in advance.

CodePudding user response:

Make a new branch starting just before the problem began ("add test files") and cherry-pick the troublesome merge commits onto it, specifying -m 1. The cherry-picked commits will be normal commits, and so you'll end up with the simple straight history you're after.


I'll demonstrate. Here we are in a situation a lot like yours:

*   11ef397 (HEAD -> main) Merge branch 'br2'
|\  
| * 4d41b17 (br2) f
| * 0486755 e
* |   1283b7e Merge branch 'br'
|\ \  
| |/  
|/|   
| * 85df598 (br) d
| * c7a4077 c
* | 5e70afb b
|/  
* 47258d5 a

Now I'll make a new branch starting at b:

% git switch -c newmain 5e70afb

Here come the cherry-picks:

% git cherry-pick -m 1 1283b7e
% git cherry-pick -m 1 11ef397

That's all. The newmain branch consists of exactly the history you want.

For completeness, let's erase our footsteps. We will delete the original main and rename newmain to main. I'll also delete br and br2 which I forgot to delete earlier when I merged them:

% git branch -D main
% git branch -M main
% git branch -D br
% git branch -D br2

And so this is what's left; there are no other commits:

* 339747e (HEAD -> main) Merge branch 'br2'
* 530f9d2 Merge branch 'br'
* 5e70afb b
* 47258d5 a

Which is exactly what you asked for.


(Warning: we have just rewritten history. In order to push this up to the remote, we will have to use force, and all collaborators must be warned in advance so that they can get ready to throw away their existing locals and clone afresh afterwards.)

CodePudding user response:

IMO, a better solution is using git push -f.

# create a new branch with current commits
git branch tmp-branch

# reset main branch to last good commit
git reset --hard <last-good-commit>

# redo merge with --squash option
git merge tmp-branch --squash

# force update to remote
git push -f origin main

  • Related