Git Squash
In Git terminology, squash means to merge or combine multiple commits into a single one. Git does not provide us with a dedicated command to squash commits. We can use the interactive Git Rebase command to squash commits.
In this tutorial, we will learn more about the need to squash and how we can squash commits.
Squashing Commits
As discussed above, squashing is the process of combining multiple commits into a single one. All the changes of the commits are added to a single commit point. Squashing commits is something that we will often do when collaborating with other developers to make our work more presentable and easy to understand. It is usually done before merging branches. Let's try to understand why we need to squash commits.
Why Squash Commits?
- Squashing is usually done to keep our commit history clean and easy to understand.
- We may work on several different branches which can have multiple commits and, merging these branches into the master branch will add a lot of commits to the history of our master branch. This will make it difficult to understand what actually is happening in our repository.
- Instead, if we squash all the commits of the branch before merging it, then we will just end up with a single commit and that commit will be added to the history of our master branch. This way we have all the changes merged with the master and we have a cleaner commit history.
- Squashing is a matter of preference and how our team wants to maintain the Git workflow.
How to Squash Git Commits?
The interactive mode of the Git Rebase command is mostly used to squash commits. We can also use the Git Merge command with the squash option to combine commits before merging. Let's learn how to use each of these commands.
Squashing Commits Using Git Rebase
- The Git Rebase command works in two modes - Standard and Interactive. The interactive mode gives us a lot of options to work with. We can squash commits by using the interactive Git Rebase. Use the -i flag with the Git Rebase command to use the interactive mode.
- We need to specify the commits that we want to squash. For example, if we have five commits(A -- B -- C -- D -- E) and we want to squash the last three commits(C, D, and E), then we will need to pass a reference to the parent of the commit C i.e. commit B. We can use the hash of commit B or the HEAD~3 notation to do this.
$ git rebase -i <commit-hash-of-parent>
$ git rebase -i HEAD~n
- The above command will open a text editor with an entry for each commit. We will now replace the word pick with the word squash to tell Git that we want to squash these commits with the previous one. Do not replace pick for the first commit as the other commits will be squashed into this commit.
- After closing this editor, another text editor will open up where we can enter the message for the squashed commit.
Consider the following practical example to better understand the above steps.
We will first view the commit history using the Git Log command.
We will now squash the last three commits. Basically, we will squash the last two commits(c875601 and 4fa3f3c) into the third commit fa82d55. We will run the Git Rebase command with the -i flag and pass the reference to the parent of the commit fa82d55. We will use the HEAD~3 notation to do this.
Git will now open up our configured text editor.
Replace the word pick by squash for the two commits to squash them with the previous one. Do not replace pick for the commit fa82d55 as we are squashing the other two commits into this one.
When we close this editor, Git will automatically open another editor where we can add a message for the squashed commit. We will keep the autogenerated message and close this editor.
Now, when we run the Git Log command we can see that the last three commits were combined into a single squashed commit. Notice that the commit hash of the last commit is different from the commits that we squashed. This indicated that Git created an entirely new commit with the changes of the three commits.
Squashing Commits Using Git Merge
- The Git Merge command has a --squash option which can be used to squash all the commits of a branch into a single one and then merge that commit to some other branch.
- Make sure to use the Git Commit command after using Git Merge to add this new squashed commit to the branch. Git will automatically provide a squash message for this commit but we can alter it.
- The --squash option will not create a merge commit and the history of the branch will only show a single new commit added to it. All the changes of the other branch will be present in that single commit.
- Make sure you are checked out on the branch to which you want to add the squashed commit i.e. the branch where you want to merge the other branch.
$ git merge --squash <branch-name>
Consider the above example where we have two branches - feature and master. The feature branch has three new commits and we want to merge them into the master branch as a single squashed commit.
We will first check out the master branch using the Git Checkout or the Git Switch command.
Next, we will use the Git Merge command with the --squash option to add a squashed commit to the master branch. This squashed commit will be composed of the three commits of the feature branch.
Now, use the Git Commit command to add this squashed commit to the master branch.
We can view the history of the master branch with the Git Log command. Notice that we only have a single new commit added to the master branch.
The message of this commit gives information about the commits that were squashed.
Summary
Squashing commits is a technique of combining multiple commits into a single one. This is done to make sure that our commit history is not too crowded and is easy to understand. When working in a team, multiple developers will be creating new features and merging them into the master branch. The master branch will end up having all the commits of all the feature branches that were created. This situation can be avoided by using squashed commits. We can squash commits in Git by using the Git Rebase and the Git Merge commands.