Git Gremlin: Squash Commits (to Make Your Git History Cleaner)

joaedwar

J Edwards

Posted on January 1, 2021

Git Gremlin: Squash Commits (to Make Your Git History Cleaner)

Git is a free and open-source distributed version control system, designed to help developers handle small to large code changes with efficiency. But, with great ease comes great opportunity for screw-ups. It is quite easy (especially for beginners) to make a small mistake with Git that can have a seemingly catastrophic effect on overall work. Some Git mistakes are more intimidating and difficult to correct than others, but fear not! There is no need to panic — you can roll back a Git disaster with some help. For the infinite number of ways one can make an error with Git, Git Gremlin provides useful tips for what to do when things don't go as planned.



User Story

As an open-source contributor, I want to group the content of a pull request, so that the commit history is neater


Scenario

When working with Git, you may want to revise your local commit history and decide what files go into which commits.
You can rewrite commits so they appear as if they occurred in a different manner. This can involve changing the order of the commits, changing messages, modifying files in a commit, or removing commits entirely , before you share your work with other contributors who have access to the repository.

For example, after using git log to view the commit history, you notice some embarrassing commits on a feature branch, similar to this:

* ed88dab Correct configuration details
* dca37d5 typo
* 46e83b5 test
* e30e77d undo mistake
* 9409777 Add configuration details
Enter fullscreen mode Exit fullscreen mode

You want to rework the history so that the output from git log looks more like this:

* ed88dab Add Test and correct configuration details
* 9409777 Add configuration details
Enter fullscreen mode Exit fullscreen mode

What is the Issue?

How can you augment the commit history so that a series of N commits are presented in a single commit?


How to Resolve the Issue?

Squashing can be used to condense a large number of commits into a smaller number of more meaningful commits, in an effort to make the git history clearer.

Squashing in Git is a technique that employs rebasing to help consolidate a series of commits. You can use git rebase to combine a sequence of commits into a new base commit. When you use rebasing to rewrite history, you are automatically applying commits in your current working branch to the passed branch head.

By making the rebase interactive (adding the -i option to git rebase) you have the opportunity to alter individual commits.

git rebase --interactive (-i for short), opens an editor with a list of the commits which can be changed as well as a list of acceptable commands - allowing the user to edit the list before initiating the rebase action. In addition to squashing a commit, the user is also presented with the following options:

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
d, drop = remove commit
Enter fullscreen mode Exit fullscreen mode

Prerequisites

  • A branch with a commit history.
  • You will need to use the terminal to execute commands.

Procedure

Use the following command to get the commit history:

git log
Enter fullscreen mode Exit fullscreen mode

The output will reflect the commits on that branch, similar to the following:

* 617c65c Fix CRD group and minor updates
* 46e95a5 WIP additional work in progress
* e30e77d WIP work in progress
* 9409666 Adding the build script
Enter fullscreen mode Exit fullscreen mode

There are WIP (Work in Progress) commits in the history that we can squash to make the Git history more concise. To interactively rebase the commits, we can use the following command:

git rebase -i HEAD~<n>
Enter fullscreen mode Exit fullscreen mode

Alternatively, you can use the command
git rebase -i <after-this-commit-sha1>.

The -i flag in the command indicates that is an interactive rebase and the <n> represents the number of commits you want to go back in your history to rewrite.

In our example, we would like to rebase all commits proceeding the initial commit, and can use the following command:

git rebase -i HEAD~3
Enter fullscreen mode Exit fullscreen mode

An interactive editor opens when the rebase process commences. The rebase command brings up an interface that presents the following options:

pick 617c65c Fix CRD group and minor updates
pick 46e95a5 WIP additional work in progress
pick e30e77d WIP work in progress

# Rebase 617c65c..e30e77d onto e30e77d (3 command(s))
# 
# 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.
#
# Note that empty commits are commented out
Enter fullscreen mode Exit fullscreen mode

The editor displays the commits in reverse order starting from 3 commits back, which is defined by HEAD~3.

In the editor, replace pick (on all commit lines except the top line) with squash.

pick 617c65c Fix CRD group and minor updates
squash 46e95a5 WIP additional work in progress
squash e30e77d WIP work in progress
Enter fullscreen mode Exit fullscreen mode

The squash command consolidates the three commits into the top commit.

Alternatively, you can use the fixup command and amend the commit message.

To save changes and exit the interactive editor, press Esc, enter : followed by x, and press Enter.

If you view the output of git log again, a single commit is displayed.


That's it! If you'd like to dive deeper, please check out more of the Git Gremlin posts. Also, the following resources are helpful for getting more comfortable with Git:

  • Git-SCM - Git reference documentation

  • Git Training - Official Git cheat sheets

  • Visual Git - A tool for exploring Git visually.

  • Git Game - A desktop application that helps you learn Git through fun challenges.

Thank you for checking out this post, and please git going!

💖 💪 🙅 🚩
joaedwar
J Edwards

Posted on January 1, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related