Too many commits? No worries, just squash them into one!
It's a beautiful Friday morning. It had just rained last night. You wake up feeling energetic and ready to build something great or make something better. You've filled your favourite mug with your favourite morning beverage, sat down on your desk and opened your laptop.
The first open issue is your pick of the day. You dove right into it. The problem is understood. It's an open and close case.
First commit. Tests are passing. You pushed to github!
Shortly after, QA report comes through that your
PR is breaking another thing not covered by currently written tests.
You create 3 more commits for the fix and some tests. More things break!
By midday, half your screen is filled up with commit messages. The day is adamant on going down in history as proof that, "a wonderful morning does not guarantee a good evening". Literally.
At the end, you manage to get everything to work:
- Tests are passing
- Static Analysis
- QA Approval
But, Your PR has 11 commits. You can't send that for a review. Its too much work for a reviewer. Have some empathy.
Luckily for you, you can fix that with the
What is the squash-rebase workflow
The principle here is, before you merge a working branch into the
main branch, all commits of the
working branch should be squashed into one single commit, then, rebased from the main branch.
These are the steps:
Select the starting commit
Couple of assumptions here:
- You are working on a
feature branchyou checked out from your project's up-to-date
- You have made all necessary changes you need to make up to your final commit.
On the feature branch, run the following command:
This is to list all the commits we have made starting from the most recent one. You will get something similar to the following on your screen:
commit e8f89c696596619678c819f9b7a34730cd3f41bb (HEAD -> chore/test-git-squashing, origin/chore/test-git-squashing) --- newer commit Author: Faruk Nasir <email@example.com> Date: Tue Apr 27 09:41:30 2021 +0100 fix: on and on and on we go commit a8293a21f31b5fea688dc3ef65add3b9924b5f28 Author: Faruk Nasir <firstname.lastname@example.org> Date: Tue Apr 27 09:41:00 2021 +0100 fix: and on we go commit 3dc51a8a8f83d96cde7b0f9b2be33c694ca91a3d Author: Faruk Nasir <email@example.com> Date: Tue Apr 27 09:40:33 2021 +0100 fix: we are adding something commit 5f561cc9380ddeafd6134cee31b4ee4f630eac4c Author: Faruk Nasir <firstname.lastname@example.org> Date: Tue Apr 27 09:40:03 2021 +0100 fix: deleted some things commit 3c0ae097ef858d61ecc2110d84a413f77673d09a (origin/main, main) --- older commit Author: Faruk Nasir <email@example.com> Date: Tue Apr 27 09:33:13 2021 +0100 chore: fifth change
Above you can easily detect where your main branch stops and where your feature branch starts. The goal here is to count all the commits of your feature branch. This will then be used in the command to start the interactive rebasing. More on that in a bit. For a more compact result of the commits' log, we can try decorating the command as in the following:
git log` or `git log --graph --decorate --pretty=oneline --abbrev-commit
This will give us:
* e8f89c6 (HEAD -> chore/test-git-squashing, origin/chore/test-git-squashing) fix: on and on and on we go * a8293a2 fix: and on we go * 3dc51a8 fix: we are adding something * 5f561cc fix: deleted some things * 3c0ae09 (origin/main, main) chore: fifth change * e1d0da7 chore: fourth change * e165870 chore: third change * f249883 chore: second change * 86b4fbd chore: first change
Picking and Squashing
After getting the number of commits you want to squash, you go ahead and run the following command to start the interactive:
git rebase --interactive HEAD~[number of commits] # or git rebase -i HEAD~[number of commits]
So, let's say you are trying to squash 4 commits, the command will look something like this:
git rebase -i HEAD~4
Alternatively, if you don't want to count the number of commits all the time, especially, when the commits are quite long, you can get the
hash of the commit just before the first one to rewrite from and run the
interactive rebasing command like this:
git rebase --interactive [commit-hash]
An editor will popup with something like the following:
pick e8f89c6 fix: on and on and on we go --- older commit pick a8293a2 fix: and on we go pick 3dc51a8 fix: we are adding something pick 5f561cc fix: deleted some things --- newer commit ...
Here, you are to edit the file leaving one commit as
pick (ususally the first one) and change all the other ones to
squash. Save and exit the editor.
New Commit Creation
You will be prompted again to enter a commit message for the final about to be created. You can choose to skip this and the name of the commit will be a list of all the intermediate commit. It will look like the following:
on and on and on we go and on we go we are adding something deleted some things
And, thats it! You have successfully squashed all your commits into one. Thank you for reading!