DEV Community

loading...
Cover image for Too many commits? No worries, just squash them into one!

Too many commits? No worries, just squash them into one!

Faruk Nasir
Updated on ・4 min read

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-date main 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

So, let's say you are trying to squash 4 commits, the command will look something like this:

git rebase -i HEAD~4
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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

...
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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]

Discussion (0)