Git Skaawsh

Ryan Graham
3 min readMay 5, 2020

--

git allows you to squash multiple commits into one.

I tend to work in dev or feature branches with pretty dirty git logs. Once my code passes tests, squash allows me to go back and combine my fragmented commits into a single atomic commit representing a feature. As a bonus git bisect will actually work once you’ve set the expectation that every commit in master should build and pass tests.

Github method — Press Button

You can wait until its time to merge your Pull Request in Github and squash the entire thing there. Just press the button and everything is done for you.

But what if someone else merges for you and they don’t select this option? Then you have to resort to other methods to clean everything up.

Textbook method — Rebase Interactive

This seems to be the way everyone is taught. Usually by an annoyed co-worker trying to help you up your game.

Lets say I have a git log with these 3 commits that I want to squash into one.

da91e29 N 2 minutes .. Ryan ..bump aurora module version again again HEAD -> staginged47202 N 18 minutes.. Ryan ..bump aurora module version again origin/staging4c82dbf N  2 hours ago Ryan ..bump aurora module version

I can pass the git range from HEAD to N commits back to git rebase.

git rebase -i HEAD~3

Then my editor will pop up with the relevant commits.

pick da91e29 bump aurora module version again again
pick ed47202 bump aurora module version again
pick df71a27 bump aurora module version

Edit to look like this and then save.

pick da91e29 bump aurora module version again again
squash ed47202 bump aurora module version again
squash df71a27 bump aurora module version

Once you’ve saved you should have one new commit in your log with the edits from all three of the old commits.

Easy, right? Well its a bit cumbersome. Not to mention intimidating for people new to git rebase. Sure fixup and autosquash can make it a little better. But there has to be a better way.

The easy way — Squash(N)

I stumbled across this git alias by EthanB a while back which soft resets N commits from HEAD and creates a new commit. And I hardly have to remember anything to use it, which is something I value highly.

git squash N

So let’s take our example commits from earlier.

da91e29 N 2 minutes .. Ryan ..bump aurora module version again again HEAD -> staginged47202 N 18 minutes.. Ryan ..bump aurora module version again origin/staging4c82dbf N  2 hours ago Ryan ..bump aurora module version

I run the alias.

git squash 3

My editor pops up, but this time all I have to do is read and approve the commit message. Looks good by default. So I save immediately and it exits. This is my new commit log.

e8583fc N 19 minutes.. Ryan ..bump aurora module version HEAD -> staging, origin/staging

Done.

So here is how you set it up. Run this in your shell.

git config --global alias.squash '!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"; };f'

Now check your git config just to confirm the alias was created.

$ cat ~/.gitconfig
[user]
name = Ryan Graham
email = <redacted>
[log]
date = relative
[format]
pretty = format:%C(auto,yellow)%h%C(auto,magenta)% G? %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(7,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D
[pull]
rebase = true
[rebase]
autosquash = true
[alias]
squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"

Never mind my config file’s user and format entries. Look for alias at the bottom. Does yours match? You’re good to go.

--

--

No responses yet