---
title: Auto-squashing Git Commits
teaser: Help your teammates and keep your Git history clean by using autosquash and
  interactive rebase to automatically squash fixup commits before merging.
tags: git,cli,teams,workflow,tools
author:
- George Brocklehurst
- thoughtbot
published_on: 2015-06-15
---

If you've read thoughtbot's [Git protocol guide][git-guide], you'll know that
once a branch has been code reviewed, we encourage the branch's author to use an
[interactive rebase][rebase-post] to squash the branch down into a few commits
with [great commit messages][commit-message-post].

It's fairly common for a feature branch to be squashed down to somewhere between
one and three commits before it's merged. If you follow this protocol, or
something like it, there are a few Git features that can make your interactive
rebases quicker and easier.

[git-guide]: https://github.com/thoughtbot/guides/tree/main/git
  "thoughtbot guides: Git protocol"
[rebase-post]: https://thoughtbot.com/blog/git-interactive-rebase-squash-amend-rewriting-history
  '"Git Interactive Rebase, Squash, Amend and Other Ways..." by Tute Costa'
[commit-message-post]: https://thoughtbot.com/blog/5-useful-tips-for-a-better-commit-message
  '"5 Useful Tips For A Better Commit Message" by Caleb Hearth'

## Automate your rebases

Often, you'll know before you commit something that it's really just an
extension of one of the other commits on your branch.

Say I have this history:

    $ git log --oneline --decorate
    ccc3333 (HEAD, my-feature-branch) A third commit
    bbb2222 A second commit
    aaa1111 A first commit
    9999999 (main) Old stuff on main

One of my pull request reviewers points out a typographical error in one of my
commits, so I thank the reviewer and fix the typo. The typo was introduced in "A
second commit", and before I merge I want to incorporate the fix into that
commit: I want future [git-blame(1)][man-git-blame] users to find a useful commit
that explains a meaningful change, and not a commit that immediately fixes a
minor mistake.

I could just commit this change with a message like "fix typo" and worry about
squashing it later, but then I have to remember which commit it fixes and
manually re-order the list of commits in my interactive rebase. Git can do
all of this automatically.

During an interactive rebase there are two ways to combine commits—`fixup` and
`squash`—and there are two corresponding options for the
[git-commit(1)][man-git-commit] command, conveniently called `--fixup` and
`--squash`. These options instruct Git to write a commit message for us,
expressing the intention that this new commit will eventually be squashed (or
fixed up) with some existing commit.

For my typo fix, there's no need to modify the original commit message so I can
use `--fixup` and pass the commit that I want my changes to become part of; it
handles the commit message for me:

    $ git add .
    $ git commit --fixup bbb2222
    [my-feature-branch ddd4444] fixup! A second commit

Here's what the history looks like now:

    $ git log --oneline --decorate
    ddd4444 (HEAD, my-feature-branch) fixup! A second commit
    ccc3333 A third commit
    bbb2222 A second commit
    aaa1111 A first commit
    9999999 (main) Old stuff on main

I've dealt with all of the feedback on my pull request, so I'm ready to rebase.
To take full advantage of the commit message `git commit --fixup` generated for
me, I need to pass the `--autosquash` option to [git-rebase(1)][man-git-rebase]
to tell Git to act on the message:

<kbd>git rebase --interactive --autosquash main</kbd>

This is still an interactive rebase, so Git will still open an editor session
where I can manipulate the commits on our branch, but the `--fixup` commit I
made is already in the correct place in the list, and already marked with the
correct action:

    pick aaa1111 A first commit
    pick bbb2222 A second commit
    fixup ddd4444 fixup! A second commit
    pick ccc3333 A third commit

[man-git-blame]: http://git-scm.com/docs/git-blame "git-blame(1) manual page"
[man-git-commit]: http://git-scm.com/docs/git-commit "git-commit(1) manual page"
[man-git-rebase]: http://git-scm.com/docs/git-rebase "git-rebase(1) manual page"

## Always be automating

Since `git rebase --interactive --autosquash` only picks up on commits with a
message that begins `fixup!` or `squash!`, and Git still gives you the chance
to move things around in your editor like a regular interactive rebase, you
might be wondering why we don't just use `--autosquash` by default?

Don't worry, Git's got you covered there too. The `rebase.autosquash` setting
will enable this useful little feature for all interactive rebases:

<kbd>git config --global rebase.autosquash true</kbd>

If you're using a recent version of [thoughtbot's dotfiles][dotfiles], then
you've already got this enabled.

[dotfiles]: https://github.com/thoughtbot/dotfiles

## Type words, not SHAs

While `--autosquash` made that interactive rebase fairly painless, it could
have been even easier.

When I ran the command `git commit --fixup`, I had to tell Git which commit my
new changes should be merged with. In the example above I used the first few
characters of the commit's SHA—`bbb2222`—lifted from the output of `git
log`, but I could have referred to the commit in any of the various ways Git
allows.

The one I reach for most often in this situation is referring to the commit
using some text that appears in its commit message: Git will interpret `:/foo`
as "the most recent commit that contained the string `foo` in the first line of
its commit message". In our example above, I could have done this:

<kbd>git commit --fixup :/second</kbd>

Because this technique finds the most recent commit that matches the search
string, it's not great for finding things a long way back in history, but it's
perfect for this kind of situation where we just want to quickly and accurately
identify one of the last half dozen commits.

## Looking to build better teams, one commit at a time?

A clean commit history is just one sign of a considerate, effective team. [Learn how thoughbot's developers can help level up and augment your team][thoughtbot-augmentation].

[thoughtbot-augmentation]: https://thoughtbot.com/services/team-augmentation "Augment your team with thoughtbot"
