Squashing git commits with interactive rebase


Nitin Venkatesh's Gravatar

Nitin Venkatesh
published March 29, 2014, 5:04 a.m.


Sometimes you want to make a gazillion little commits to keep track of your project and then later on you wish you could combine them into a single commit. This comes in especially handy when you are working on code in a public repository. You don't want to see every little change you make reflected in the logs, it's just too messy. This is where git's interactive rebase comes in handy.

Let me walk you through an example to show you how you could squash your commits into one. The scenario is I add a bunch of files, each with a commit message of it's own. I now want my git repository to look as if it's just one commit that adds all the files.

First off I am going to initialize git in a repository and keep adding new files and making new commits.

$ git init
$ touch one two three four
$ git add one
$ git commit -m "First commit"
....

I keep going on like that and end up with a few commits in my repository.

nitin@jane-saucy:~/temp$ git log --oneline
fc8dd21 fourth commit
2ae6b4b third commit
723df3c second commit
7c9276a first commit
c602cfa Initial commit

Now I use the command git rebase -i HEAD~4 to work on the last four commits from the current position of my HEAD pointer.

$ git rebase -i HEAD~4

This fires up my default text editor (nano) so that I can edit stuff. I change the first three lines, from first commit to the third commit and change their first field to squash.

Note: Interactive rebase gives you a lot of options but since we want to just make it look like all our changes are just one big commit, we're using squash

squash 7c9276a first commit
squash 723df3c second commit
squash 2ae6b4b third commit
pick fc8dd21 fourth commit

# Rebase c602cfa..fc8dd21 onto c602cfa
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#

Once you save and exit the editor, and things are successful, you're met with another screen opened in your text editor. You now have the option to edit the commit message. By default, interactive rebase will provide you with the list of all the commit messages you've chosen to rebase. In my case, I have commented out all the messages and added a new one - Adds new files.

==========================================================

# This is a combination of 4 commits.
# The first commit's message is:
# first commit
# This is the 2nd commit message:
# second commit
# This is the 3rd commit message:
# third commit
# This is the 4th commit message:
# fourth commit

Adds new files

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# HEAD detached from 7c9276a
# You are currently editing a commit while rebasing branch 'master' on 'c602cfa$
#
# Changes to be committed:
#   (use "git reset HEAD^1 <file>..." to unstage)

================================================================

Now exit and save your editor and you'll see output similar to what you see below.

[detached HEAD 9632495] Adds new files
 4 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 four
 create mode 100644 one
 create mode 100644 three
 create mode 100644 two
Successfully rebased and updated refs/heads/master.

Taking a quick look at the log shows you that all your commits are now squashed into one.

nitin@jane-saucy:~/temp$ git log --oneline
9632495 Adds new files
c602cfa Initial commit