Git Squash
Overview
Git squashing is a Git feature that allows a developer to merge consecutive commits into a single commit (known as the base commit). This allows developers to maintain a clean Git project tree. The term squash is used to describe the process of squeezing multiple previous commits into a single commit.
Prerequisite
To understand the concept of git squashing, you should be familiar with the basic commit command i.e git commit. Git Commit is the most commonly used command in Git and is used to create point-in-time snapshots of staged changes to Git repositories. This works like a save point. That means you can always go back to that point. Git checks before you change it, so it's considered a safe version of your project. Changes to be considered for commitment should be in the staging area. Because staging allows you to save for preview before committing. If you want to push these changes to your git repository, you can use the git commit command to record these changes.
Commits help track the history and changes in your project repository. It can be useful if you want to come back later, find an error, or want to make some changes.
Each commit has a unique commit ID that is automatically generated at commit time. A commit ID is an encrypted number generated using a secure hashing algorithm, also known as SHA.
The command used to commit in Git is:
Now you can use the commit command's -m option to write a commit message to the command line. Commits should always include a message. This provides an overview and description of the changes being committed, making it easy for other users to see when and what was changed.
Some other famous git commands are listed in the table below:
Command | Function |
---|---|
git init | Used to create a local new git repository |
git add | Used to add untracked files to the staging area |
git commit | Used to commit the staged changes to the remote git repository |
git status | Used to show the current status of the working directory and the staging area |
git push origin main | Used to push the committed changes to the main branch of the remote repository. |
What is Git Squash?
Git Squash is not a command, it's a feature available to you in git which helps you to squash (merge) multiple previous commits into a single commit. This can help developers to maintain a clean working git tree as multiple small commits will be replaced by a single base commit. The squashing technique is very useful when you are working on a group project and you need to push group-specific changes, so it's a good habit to squash multiple small commits into one before forwarding them to others.
As you can see in the example above, changes from commits B, C, and D are included in commit E. Git squash modifies the history of the repository and can also lose commit granularity after squashing commits. Therefore, it's recommended to make minimum squashes with git.
Git squashing can be sometimes very useful, let's understand this with the help of an example:
You are working on a very tight delivery of a project and because of that, you make a lot of commits, sometimes as if you forgot to mention comments, or maybe to change the variable name. In the end, maybe you should have had fewer commits than you have, and you don’t know how to fix it. Then, git squashing will work like a charm in that situation.
To summarize, git squash is a popular git feature that allows a developer to simplify the git tree by merging sequential commits into one another. In this article, we will see how we can use squashing to merge the commits.
Git Squash Commits
As we know, git squash is itself not a command, instead, it is a git feature available to help you in cases when you have many unnecessary small changes committed to squash them all into a single larger commit.
So, there is no explicit Git squash command. Instead, we can use the interactive git rebase option to perform the squashing of commits.
For doing so, firstly, we can check the history of commits in a working git repository by using the command:
After getting the list of commits, we can choose the commits we want to squash.
Now, let's suppose we want to squash the last 4 commits, then, we can run the below command:
Here, we can replace the value with 4 as we want four commits to squash.
The above command will open a text editor, we can update the commit message of the base commit and can save and exit from the editor. Make sure that the commit message of the base commit should show the information for all the commits squashed ad it is the combination of all the commits squashed (as 4 in our example).
To confirm, you can now check the git log command. Instead of the last 4 commits, it shows the last commit.
Now, we can push this squashed commit on the remote server by running the below command:
The above command will push the changes to the remote server.
When to Squash Commits?
Squashing is used to maintain a clean Git repository. Let us understand the use case with the above example. Let's assume that we are working on a feature with group-specific tasks. Because of this, we may have multiple commits for some fixes, comments, and tests.
However, we know that many commits look similar and redundant, each one holding a minor change. In this case, you can merge multiple commits into one before forwarding/pushing. This is when squashing is used.
How to Squash Commits?
Some modern IDEs, such as IntelliJ or Eclipse, explicitly include built-in integrated support for squashing the commits from a GUI, so from there, we can directly select the commits we want to squash and then choose the option to Squash Commits by right-clicking.
However, in this article we will focus on the concept of git squashing with git commands:
As we know that Git Squash is not a command, it's only a term or a feature in git. We will see two different approaches to performing the squashing of commits:
- With the help of an interactive git rebase command.
- With the help of merging with -the squash option,
Each method is described in detail in the following sections of this article.
Squashing by Interactive Rebase
As we have seen, this option is used for squashing in the above section. Let's understand this with the help of an example.
First, let's check the commit history, and run the below command:
The output of the above command is:
Next, let's mention how many recent commits we want to squash. Suppose we want to squash all the commits A, B, C, and D into a single base commit.
For that, we can run the command:
This command opens a standard text editor showing the commit messages of the commits you want to squash, allowing you to edit them by replacing them with new commit messages that are a combination of multiple consecutive commits. You can change the pick command of commits into s or squash to squash them in the text editor. Then, you can save your changes and exit the text editor.
You can now check your commit history with the git log command. The output looks like this:
From the above output, we can see that multiple commits (A, B, and C) have been merged into a single commit D.
You can push this squashed commit on the remote server.
The above command will push the changes to the remote server.
Now, consider the case when there are a large number of commits we want to squash and it is not easy to count the number. Then, we can find the commit id or the commit hash for the commit we want to rebase "onto", and run the same interactive git rebase command by replacing the count with the commit hash, keeping all other processes the same as discussed above:
Let's see the above case with the help of an example,
The above command will display a list of commits in the commit history.
Now let's say we would like to squash all commits and rebase onto the commit ac7dd5f with the message: Commit D. So, we don't have to count how many commits we need to squash. Instead, we can just execute the command:
Follow the same steps you learned to change the pick command to squash in your default text editor, and git will perform the squash operation for you. After a successful squash, you can check the commit logs by using the command:
The output looks like this:
Squashing by Merging With the –squash Option
We have seen how to use the git rebase interactive method for squashing commits. But sometimes, we make too many commits in our local feature branch while working on it, and we need to merge it with the main branch, after completing the work. So, one way is to perform squashing on the commits of the feature branch using the git interactive rebase method and then merge the feature branch with the main branch. Another way of doing this is to merge the feature branch with the main branch along with squashing the commits. This section describes this method of squashing by merging it with the -squash option.
Let's understand this with an example:
As the output shows, we have implemented the feature in the feature branch, and we have made 4 commits. Now, we want to merge the result of the feature branch back to the main branch with only a single commit to keep the commit history of the main branch clean.
For that, we will first check out the main branch as we want to merge the changes there:
In our case,
Now, to merge the changes:
In our case, its the feature branch
The above command, we do not run like a regular merge command, git won't automatically create a merge commit, instead, it turns all the commit changes from the source branch, here in our case, it's the feature branch, into the local uncommitted changes in the working copy. We can check this by calling the command:
We need to commit the changes to the feature branch to complete the merge process.
This will complete the commit of the squashed base commit. Changes are merged automatically, and the smaller commits in the feature branch are merged into a single base commit.
You can check the history of commits:
We can see all the changes of the feature branch are merged into the main branch, with a single commit with id 565b254 in the main branch.
The feature branch still has 4 commits.
Warning about Local and Remote Commit History Mismatch
The concept of squashing can help you maintain a clean git tree, but, sometimes, it can be dangerous when your branch is already pushed to the remote repository as you are modifying the commit history. It's always a good idea to squash the commits of your local branch before pushing your changes to a remote branch.
Sometimes if it's already pushed, then you need to force the changes to the remote branch after squashing the commits of a local branch since the local commit history and the remote commit history of the branch are different.
We can push the changes from the local branch to the remote branch by using:
After performing a squash operation, you should always push changes from local to remote to get a similar commit history.
Conclusion
- Git Squash is a powerful Git feature used to select multiple commits and squash them into one big commit.
- Squashing allows developers to maintain a clean Git project tree.
- Git squash is itself not a command, instead it is a git feature available to help you in squashing unnecessary small commits into a single big commit.
- Some modern IDEs like IntelliJ and Eclipse support squashing commits directly by selecting them from the GUI.
- You can squash commits using the interactive Git rebase command.
- You can also perform squashing by merging with the –squash option.
- After squashing commits locally, you should always push changes from local to remote to get a similar commit history.
- If you want to merge the changes in the feature branch into the "main" branch and squash the commits at the same time, you can use the -squash option.
- Squashing gives you the freedom of what your project history looks like.