Halvor William Sanden

Git squash and rebase

Git squash takes your commits and squashes them together, usually into one commit. Useful for creating one commit if you've got a lot of smaller commits that creates a messy Git history.

Git rebase takes your branch and places it at the tip of the master branch (or whatever branch you rebase on). Useful for when the master has been changed since you branched off, an now want to have those changes in what you are working on as well. I usually do this before deploying to testing environments and making pull requests. It's a nice workflow for catching merge conflicts and ensuring that what you deploy and test is based on the current version.

Git squash and rebase can be done separately, but are often used together in order to have only one commit that is based on - and merged into - the newest version of master. Like many other things in Git, you can control what happens in these two processes.

I squash all commits into one when:

  • The process has been messy.
  • It makes sense to have one commit with all the changes.
  • Teammates would have to sift through the process, bugs, reverts, build errors and stuff I forgot to include. A year or six from now, they just want to see the changes and why.
  • I don't have time to do well-planned commits and put much effort into every commit message along the way.
  • It can help me making smaller pull requests.

I don't squash when the commits makes sense on their own, there is a point not to make huge commits, but commits that do only a few specific things.

I either merge along the way, maybe so I end up with a couple commits on a branc. Or I select squashing when merging a pull request in GitHub (Bitbucket offers this as well). Rebasing can also be done from the same menu.

Git squash #

This CLI example will squash four commits into one. Before starting, I make sure the last commit builds and passes the tests. This is not the only way to do it, but the one I use – and for the sake of simplicity I'm not introducing alternatives.

I go to (checkout) my branch and view the commit log.

$ git checkout branch-name
$ git log

I count my commits. Four. I want to squash them interactively from the HEAD position.

$ git rebase -i HEAD~4

I'm presented with a rebase document in my editor, not unlike a commit message. I choose what to do with each commit. The document has instructions for different commands. I want to squash the second, third and fourth into the topmost one, so I keep that at pick, the others I change to squash. Save and close.

pick 01983eca Add navigation
squash je87eu3 Fix logo position bug
squash 109oklw Increase line height
squash 37h861g Set active state for default page

A new jumbo commit message opens up. It contains the four commit messages and I combine, edit and write a new message. Save and close again to finish.

I can then either push it and make a pull request, or I can rebase it in order to continue work or test it. If the branch has been pushed previously, I make sure I'm still on the active branch and do a force push (and make lightsaber sounds).

$ git push --force

Git rebase #

In order to rebase, I need the latest master branch. Checkout master, pull down the latest updates and checkout the active branch again.

$ git checkout master
$ git pull master
$ git checkout branch-name 

Then rebase and force push the branch (don't make lightsaber sounds twice, it's only funny the first time).

$ git rebase master
$ git push --force

If there are any rebase conflicts, I either use git rebase --skip, git rebase --abort or resolve them and use git rebase --continue. I usually also build locally and deploy to testing once more.