Git is an invaluable tool when working on a code project involving multiple people. Version control provides a comprehensive history of a project, allowing you to trace its development from the beginning, letting you see who changed what, and also letting you go back in time to a specific version whenever you want. However, sometimes the history becomes cluttered, and it’s hard to get a comprehensive overview of the project, thanks to the hundreds of irrelevant commits. Developers can sometimes get a little overzealous when making them! Git squash commits are meant to solve this problem.
A git squash takes a number of previous commits, and merges them into a single commit, using a comment that makes sense. There are many situations in which this is useful, but on the other hand, there are those who think that commits should never be modified, as it results in a loss of information. I’ll explore the discussion further below, once I’ve shown you how to use git squash commits.
Using Git Squash Commits
To explain how git squash commits work, let’s start with a brand new project. I’ve first created a few commits with comments, then show you how to squash them together to create a “summary commit” that hides the details of the individual ones.
Note: I’m going to assume that you’ve already installed git on Linux and know how to use basic git commands, and maybe even connect your VPS to GitHub.
Step 1: Create the Git Repo
The first step is to create our git repo. We do this with the following code:
mkdir git-squash-demo cd git-squash-demo git init
This will create a git repo in our new folder as shown here:
Step 2: Creating a File and Making Some Commits
Now let’s create a file in this repo and make a few commits as shown here:
touch example.txt echo "Line 1" > example.txt git add example.txt git commit -m "Add Line 1" echo "Line 2" >> example.txt git add example.txt git commit -m "Add Line 2" echo "Line 3" >> example.txt git add example.txt git commit -m "Add Line 3"
In the above example, I create three lines and commit each of them with the message “Add Line x”. You can see below, that the file now consists of three lines:
At any time, we can see the history of the commits by typing:
git log --oneline
Here we can see that we have made three commits. The current “head” is at the third commit where we added line three.
Step 3: Squashing the Commits Together
Now the stage is set for our example. It’s superfluous to have three separate commits each adding one line. Wouldn’t it be cleaner to have just a single commit for all three lines? Particularly since we created all three lines one after the other. A person reading a compacted commit history would get a better idea of the evolution of the file without getting bogged down in details.
To “squash” the previous three commits down to a single commit, we use the following command:
git rebase -i HEAD~2
This command will take the last two commits and “squash” them into the first one. After typing the above command, we see this:
You can see in the blue comments section, that the commit IDs from the first to the third will be “rebased” onto the first commit, with ID number 4f89f57.
To make the squash happen, we need to replace “pick” as shown above, with “squash” for the commits we want to merge with the top-level comment. So just use the text editor to replace the words as shown here:
Press “Ctrl+X” to exit out of the editor, and when prompted, press “Y” to save your changes, then hit “Enter” for the nano editor. If done correctly, this will immediately open a new editor where you can change the commit message for the combined commit as shown here:
Now just add in the new combined commit message like this:
Save your changes as before, and you’re done! Now, you can check the git log to confirm that the commits for lines 2 and 3 have indeed been changed. We can’t change the commit for line one, because that’s the “base” commit and we have to leave it intact. Here’s what you see when you get the new git log:
As you can see, the squash worked!
The Importance of Clean Git Commits
A commit in a git repository is a way of saving your progress on a project. Along with the commit message, it’s a vital part of a project’s history, and has many benefits not just during the immediate development phase, but also during the subsequent maintenance phase if you need to work out bugs or explain the project history to someone.
So it’s worth taking a look at why the squash command is important, by understanding the role that commits play in good project maintenance.
Track the Evolution of a Project
When you’re the sole developer of a project, it’s easy for you to know everything about it and how it evolved – naturally, since it’s all in your head! But most medium to large-sized projects are developed by teams of people, several of whom rotate in and out. It’s not uncommon for video games, for example, to take several years to develop, often starting and stopping along the way. Without any context, it becomes impossible to get a bird’s eye view of how the project evolved.
A solid commit history, however, can act as a kind of meta-narrative for the project, marking out the major milestones, and showing the big events such as code refactoring, etc. The ability to go back to a certain point in time and see what changed is invaluable when you’re trying to understand why a particular change was made so that you don’t end up making the same mistakes again.
Invaluable in Debugging
While debugging, you can use a copious commit history to invoke tools like “git bisect”, which lets you narrow down the point at which the code started to malfunction. This makes even hidden bugs relatively easy to pinpoint, even if they were introduced a long time ago. There’s no guarantee that a bug introduced by a specific commit will be noticed during the testing phase of that commit, and before the next commit is introduced. In fact, it might be a long time before you notice it, and the bug could even run over into production!
A solid commit history lets you track bugs and commits that introduced them, making everyone’s life easier.
The above importance of commits illustrates the necessity of keeping a clean commit history. Despite philosophical objections about maintaining the “purity” of the commit history, there exists a balance between the two extremes. No one is suggesting that we use the git squash command to erase substantial portions of commits or even most of them. The idea is simply to remove superfluous commits so that the project has a readable history and can usefully serve as a meta-narrative on its own.
I’m a NameHero team member, and an expert on WordPress and web hosting. I’ve been in this industry since 2008. I’ve also developed apps on Android and have written extensive tutorials on managing Linux servers. You can contact me on my website WP-Tweaks.com!