What is git squash and how to squash?

You would use “git squash” when you want to combine multiple commits into one single commit. The goal is to tidy up your commits usually. 

To squash your commits, you can use “git rebase -i” first to get the list of commits in an editor, then change the commits from “pick” to “squash” for the commits that follow the first commit that you want to squash and then save. All the commits will squash into the commit that was above these.

Let us see this whole process step-by-step on a real machine.

The initial setup is as shown. Use “git log –oneline” to list all the commits in the repository “repoone“.

We aim to squash commits 3f54558bead66e27658cfand 9870df7 into one commit.

~/repoone$ git log --oneline
d0978f9 (HEAD -> main, origin/main, origin/HEAD) Sixth line in newfile
9870df7 Update newfile
27658cf Fourth line added in newfile
bead66e Another change to new file
3f54558 This is new file
4632c0d Adding empty directory
908d6ac Third commit in main
42296d0 Second commit in main
453424e This is first commit
2673111 Initial commit

Pick a commit that is older than these commits to list all the later commits in the editor. We chose 4632c0d so that git displays all the commits above in the editor.

~/repoone$ git rebase -i 4632c0d

Choose the three commits after the first commit, and change “pick” to “squash“.

pick 3f54558 This is new file
squash bead66e Another change to new file
squash 27658cf Fourth line added in newfile
squash 9870df7 Update newfile
pick d0978f9 Sixth line in newfile

# Rebase 4632c0d..d0978f9 onto 4632c0d (5 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 [-C | -c] <commit> = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but
#                    opens the editor
# 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.
#

Press Save or Close based on your editor and git setup. It would display a commit message.

# This is a combination of 4 commits.
# This is the 1st commit message:

This is new file
# This is the commit message #2:

Another change to new file
# This is the commit message #3:

Fourth line added in newfile
# This is the commit message #4:

Update newfile

Fifth line in newfile

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Author:    codeversionmaster <112749588+codeversionmaster@users.noreply.github.com>
# Date:      Sat Oct 15 21:25:35 2022 +0530
#
# interactive rebase in progress; onto 4632c0d
# Last commands done (4 commands done):
#    squash 27658cf Fourth line added in newfile
#    squash 9870df7 Update newfile
# Next command to do (1 remaining command):
#    pick d0978f9 Sixth line in newfile
# You are currently rebasing branch 'main' on '4632c0d'.
#
# Changes to be committed:
#       new file:   newfile
#

Press Save or Close based on your editor and git setup. It would display the rebase status as shown.

[detached HEAD 0516dab] This is new file
 Author: codeversionmaster <112749588+codeversionmaster@users.noreply.github.com>
 Date: Sat Oct 15 21:25:35 2022 +0530
 1 file changed, 5 insertions(+)
 create mode 100644 newfile
Successfully rebased and updated refs/heads/main.

Now you can list the commits using “git log –oneline“. The three commits marked as “squash” no more appear, and they got squashed into the commit just before them, i.e., the commit with the message “0516dab This is new file”.

~/repoone$ git log --oneline
378e483 (HEAD -> main) Sixth line in newfile
0516dab This is new file
4632c0d Adding empty directory
908d6ac Third commit in main
42296d0 Second commit in main
453424e This is first commit
2673111 Initial commit

You can do “git show” on the top commit of these three squashed commits. You can see it would have all the commit messages and changes.


~/repoone$ git show 0516dab
commit 0516dabb7cb7a9f69f97d10bd66f5d44d5345058
Author: codeversionmaster <112749588+codeversionmaster@users.noreply.github.com>
Date:   Sat Oct 15 21:25:35 2022 +0530

    This is new file

    Another change to new file

    Fourth line added in newfile

    Update newfile

    Fifth line in newfile

diff --git a/newfile b/newfile
new file mode 100644
index 0000000..66ac9df
--- /dev/null
+++ b/newfile
@@ -0,0 +1,5 @@
+This is new file
+Another change added to this file
+
+This is fourth line
+This is fifth line

That’s it.