Too many commits? No worries, just squash them into one!
Faruk Nasir
Posted on April 27, 2021
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!
Shoooosh!
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:
- [x] Tests are passing
- [x] Static Analysis
- [x] 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 squash-rebase workflow
.
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 branch
you checked out from your project's up-to-datemain branch
. - You have made all necessary changes you need to make up to your final commit.
On the feature branch, run the following command:
git log
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 <user@example.com>
Date: Tue Apr 27 09:41:30 2021 +0100
fix: on and on and on we go
commit a8293a21f31b5fea688dc3ef65add3b9924b5f28
Author: Faruk Nasir <user@example.com>
Date: Tue Apr 27 09:41:00 2021 +0100
fix: and on we go
commit 3dc51a8a8f83d96cde7b0f9b2be33c694ca91a3d
Author: Faruk Nasir <user@example.com>
Date: Tue Apr 27 09:40:33 2021 +0100
fix: we are adding something
commit 5f561cc9380ddeafd6134cee31b4ee4f630eac4c
Author: Faruk Nasir <user@example.com>
Date: Tue Apr 27 09:40:03 2021 +0100
fix: deleted some things
commit 3c0ae097ef858d61ecc2110d84a413f77673d09a (origin/main, main) --- older commit
Author: Faruk Nasir <user@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 s
or 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!
This post first appeared (here)[https://faruknasir.com/2021/4/squash-commits-into-one-git]
Posted on April 27, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.