Musings of an 8-bit Vet

A Student Coders Tech Diary

Tame Git Commits With Squash

In class we are working our way through the Ruby Koans. This is partly to learn Ruby, and partly to get us used to making git commits and doing pull requests.

While exploring the section “about_regular_expressions” and fixing each test and doing some Gitx practice, I found myself the proud owner of 27 separate commits!

At this point Jason Noble, our instructor, stepped in and said something like “Wow, that’s a lot of commits. You should git rebase -i and squash some of them.”

What is squash, you ask? It is where you take a number of commits and turn them into a single commit, combining the commit messages at the same time.

In the following example, lines 3-7 are five commits I performed:

1
2
3
4
5
6
7
8
9
[~/workspace/squash_reword]
(master) $ git log --oneline
d3d80ce Add README file
b209207 Include testing file
53ca0f5 Env >> file.txt
1962bf9 Add another_file.txt
44d0164 Initial commit
[~/workspace/squash_reword]
(master) $

Issuing the following command: git rebase -i HEAD~4 make the default editor editor open up git-rebase-todo with the following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pick 1962bf9 Add another_file.txt
pick 53ca0f5 Env >> file.txt
pick b209207 Include testing file
pick d3d80ce Add README file

# Rebase 44d0164..d3d80ce onto 44d0164
#
# 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.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

I used HEAD ~4 to tell rebase to count four commits from HEAD. If you are rebasing against a remote you would use something like git rebase -i upstream/master.

The instructions on how to use all these features are in the comments below the list of commits. Change pick to squash on the commits you want to combine, and save your changes.

WARNING: Do NOT change the first line! Bad things happen.

1
2
3
4
5
6
pick 1962bf9 Add another_file.txt
squash 53ca0f5 Env >> file.txt
squash b209207 Include testing file
squash d3d80ce Add README file

# Rebase 44d0164..d3d80ce onto 44d0164

Upon closing the editor, you will be presented with the file COMMIT_EDITMSG containing all the messages from the squashed commits:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# This is a combination of 4 commits.
# The first commit's message is:
Add another_file.txt

# This is the 2nd commit message:

Env >> file.txt

# This is the 3rd commit message:

Include testing file

# This is the 4th commit message:

Add README file

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# HEAD detached from 1962bf9
# You are currently editing a commit while rebasing branch 'master' on '44d0164'.
#
# Changes to be committed:
#   (use "git reset HEAD^1 <file>..." to unstage)
#
# new file:   README.md
# new file:   another_file.txt
# modified:   file1.txt
# new file:   file_spec.spec

Edit the new single commit message, and remove any duplicated or extraneous text, and hit save and close the file. Git will update the files and adjust the commit. Your list of commits now looks like this:

1
2
3
4
5
(master) $ git log --oneline
5dd5037 Add README and testing files
44d0164 Initial commit
[~/workspace/squash_reword]
(master) $

Problem solved!

You can also use the same procedure to edit commit messages, only use the option reword instead of pick.