Squashing commits

Now let's see how we can squash commits. Squashing commits is the process of taking two or more commits, and combining all the changes in those commits into a single commit. For example, here we will squash commits 78af47a, 7f4e64b, and 2a57b17 into a single commit. To do this, we use interactive rebasing. So we run

git rebase -i ab0e842

where commit ab0e842 is the parent of the oldest commit that we wish to squash.

Squashing commits 1

To squash two commits together we need to use the squash option in VS Code. Notice how GitLens is not showing us which commits will be squashed into which commit by simplifying the commit tree. One thing to remember here is that squashing is an operation that can only be performed between two consecutive commits. So once the rebasing starts, Git will first squash commit 7f4e64b into commit 78af47a, and then squash commit 2a57b17 into the new commit that it created for the first squashing. If we want to squash commits that are not consecutive to one another, then we first need to reorder the commits.

Squashing commits 2
Squashing commits 3

When we close VS Code and the rebasing starts, Git will ask us to give the new commit a message. The default message that it will show is the combination of the commit messages for all the commits that we are squashing. In general, since we squash commits that have changes that we should have made into a single commit to begin with, we should input a new message that reflects the changes done across all of the commits been squashed.


Now if we look at our log there is only one commit for all three sets of changes.

If we already know that the message for our squashed commit is the message for the oldest commit, then we can use the fixup option instead of the squash option. To see this in action, first we need to reset our repository to how it was before the last rebasing. So we bring up our reflog by running

git reflog

and grab the commit ID to which the HEAD pointer was pointing, before starting the rebase. In this case, commit d038481 (which is the finish of the last rebase we did).

Squashing commits 4
Squashing commits 5

Now we use

git reset --hard d038481

and our repository will be restored to the state before the last rebase. We can see this in our log.

Now we restart the interactive rebase just as before, but when Git asks us which operation to perform to the commits to squash, we choose fixup. This will cause Git to ignore the commit messages from these commits, and thus default to the commit that they are being squashed into (the one with the pick operation).

Squashing commits 6
Squashing commits 7

Since there are no conflicts for us to resolve, as soon as we save and close the file, Git will complete the rebasing process. If we now check the log, we can see that the commits have been squashed, and the message of the oldest commit was kept without us having to tell Git which message to use.