How to Git Squash Commits?

Writing a git commit can be hard, so sometimes we just write small commits and push the changes. However, if we look back at the commit message, we may get the idea to clean it up. Luckily, there is a feature on git that allows us to do that.

Squash Commits

You might write small commit message like this.

git add .
git commit -m "docs: update readme"
git push

This is an example of the Git commit history of one of my Git repositories.

git log --oneline

1e3c6d1 doc: update readme
07df308 doc: update readme
9372264 doc: update logo
59e1df2 doc: update logo
122be6a doc: update logo

Git Rebase

In this case is better to merge two or more commit into one commit since they are have the same message. So for that we can do squash commit. Here's how you can do that.

git rebase -I HEAD~5

This Git command will pick the last five commits, and then we can do a squash commit. If you run that command, it will display this message.

pick 1e3c6d1 doc: update readme
pick 07df308 doc: update readme
pick 9372264 doc: update logo
pick 59e1df2 doc: update logo
pick 122be6a doc: update logo

# Rebase 1e3c6d1..122be6a onto 85f6cdb (10 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted

As you can see, there are several operations that we can use to manipulate the commit message.

pick 1e3c6d1 doc: update readme
fixup 07df308 doc: update readme
pick 9372264 doc: update logo
fixup 59e1df2 doc: update logo
fixup 122be6a doc: update logo

So, in this case, we want to delete duplicate commits, so we use the fixup operation. The commit will look like this.

1e3c6d1 doc: update readme
9372264 doc: update logo

After doing squash commit we need to force push since it updating the commit history, it like delete the commit history.

git push origin main --force

Yes, that's how you can clean up your commit history. See you in the next article.