Git Gremlin: Squash Commits (to Make Your Git History Cleaner)
Tags: git, github
Published: 2021-01-01 23:50:46

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](#user-story)
* [Scenario](#scenario)
* [Issue](#what-is-the-issue) 
* [Resolution](#how-to-resolve-the-issue)
* [Prerequisites](#prerequisites)
* [Procedure](#procedure)

_____________________________________________________________
### 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
```

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
```

### 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
```

#### 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
```
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
```

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>
```

> 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
```

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
```
> 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
```

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 <kbd>Esc</kbd>, enter `:` followed by `x`, and press <kbd>Enter</kbd>.

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](https://git-scm.com/) - Git reference documentation

* [Git Training](https://training.github.com/) - Official Git cheat sheets 

* [Visual Git](https://git-school.github.io/visualizing-git) - A tool for exploring Git visually.

* [Git Game](https://github.com/jlord/git-it-electron) - A desktop application that helps you learn Git through fun challenges.

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