Squashing commits

By Will Braynen

Illustration by Donna Blumenfeld

Illustration by Donna Blumenfeld

Scenario

SourceTree screenshot, with commits listed in reverse chronological order. If you prefer to view git history from the terminal, you could use this command: `git log` or `git log --date=short --pretty=format:"%h%x09%an%x09%ad%x09%s"`

SourceTree screenshot, with commits listed in reverse chronological order. If you prefer to view git history from the terminal, you could use this command: `git log` or `git log --date=short --pretty=format:"%h%x09%an%x09%ad%x09%s"`

In other words, you branched off master to create a feature branch called “transaction-confirmation-modal-dialog”. (For simplicity, let’s assume that you are the only one working in this feature branch, so there is no need to branch further.) You then made the following three commits to your feature branch:

  1. “Added cancel button” (your first commit)

  2. “Added OK button” (your second commit)

  3. “Wired up business logic” (your last commit)

After three commits and successful PR review (that is, peer code review via a pull request), you are now ready to merge your feature branch back to master. At the time it made sense to have small commits, for example to be able to retrace your steps if you messed something up. But, for the sake of a manageable and useful git history, you are now wishing your three commits were just one commit, so that you would just merge one commit to master instead of three. Something with a commit message like “Added a modal dialog for transaction confirmation.” After all, let’s assume, if you were later to revert this work because it introduced a bug, you would revert the entire feature and not one of these microcommits.

So how do you combine these three consecutive commits into one?

Solution

Interactive rebase to the rescue! Here is what it looks like from the terminal:

$ git rebase -i HEAD~3

The “3” here means that you want to combine the last three commits. This will bring up your default git editor, so make sure you have your default git editor set to something you know how to use. In your editor, you will see something like this:

pick 976f885 Added cancel button
pick 4c4deab Added OK button
pick 94d9369 Wired up business logic

Everything else you will see will either be a blank line or will start with the “#”, which means it’s a comment that will be ignored by git; so this everything else you can ignore.

Notice that, unlike my SourceTree screenshot, this shows your commits in chronological order instead of reverse chronological order. For your last two commits, replace “pick” with “s”. (“s” for squash; although, if you like typing, I think you can write out “squash” in full instead.) You should end up with this:

pick 976f885 Added cancel button
s 4c4deab Added OK button
s 94d9369 Wired up business logic

This means take the last two commits (“Wired up business logic” and “Added OK button”) and squash them into your first commit (which was “Added cancel button”). In other words, you are combining your last two commits with your first. Save and exit.

Your editor will now show you the three commit messages and give you a chance to delete them and write a brand new one. Let’s assume your new commit message is: “Added a modal dialog for transaction confirmation”. (Remember, everything that starts with a “#” is a comment that’s ignored by git.) . Again, save and exit.

Voilà! You should now see the following git history instead of what we started with:

SourceTree screenshot - result

You are now ready to merge your feature branch to master.

______
P. S. Morgan left a really good comment below, but the formatting got lost for some reason. I even contacted squarespace support about it. So, an illustration to her comment:

$ git reflog
$ git reset --hard HEAD@{8}

or if not “8”, then whatever the number is in the list “git reflog” returns that corresponds to the step to which you want to reset.