We often need to squash several related commits to make the commit history cleaner. There are several different ways to achieve this.

Here, suppose we want to squash last 2 commits.

Using git rebase

I have covered this method in my previous post, so I won’t repeat it here.

soft reset, then commit

First, we run the soft reset command:

git reset --soft HEAD~2

This will reset last two commits, but keep their changes. If you run git status command, you will see that you have uncommitted changes. These changes are a combination of changes in last two commits.

Now, you just commit again and write the new commit message:

git commit -m "some msg blah blah blah"

hard reset, then merge –squash

First, we run the hard reset command:

git reset --hard HEAD~2

This will discard changes in the recent two commits, but there are actually not lost. HEAD@{1} represents where your HEAD was before you use hard reset. HEAD@{2} represents your HEAD two moves ago. So HEAD@{} variable logs your HEAD movement. We can check the HEAD movement using git reflog. An example output is like this:

0073058 (HEAD -> master) HEAD@{0}: commit: 9th
618c9fd HEAD@{1}: commit: 8th
ed79391 HEAD@{2}: commit: Squashed commit of the following:
f0fb17b HEAD@{3}: reset: moving to HEAD~2
b2ee13a HEAD@{4}: reset: moving to HEAD
b2ee13a HEAD@{5}: reset: moving to HEAD
b2ee13a HEAD@{6}: reset: moving to HEAD
b2ee13a HEAD@{7}: reset: moving to HEAD
b2ee13a HEAD@{8}: reset: moving to HEAD
b2ee13a HEAD@{9}: reset: moving to HEAD
b2ee13a HEAD@{10}: reset: moving to HEAD
b2ee13a HEAD@{11}: commit: 7th
004a853 HEAD@{12}: commit: sixth
f0fb17b HEAD@{13}: commit: fifth
d9f10ed HEAD@{14}: commit: fourth
774b308 HEAD@{15}: commit: thrid
ad2fb58 HEAD@{16}: commit: second
efe6902 HEAD@{17}: commit (initial): first

Now, we will run git merge --squash HEAD@{1} to squash the recent two commits. The merge window should be pre-populated with the commit message of recent two commits.

References