I hate squash and merge with a burning passion

Now, let’s be perfectly clear. Using git merge --squash is not always a bad thing, the premise being that

But let’s be real. We already had a tool for squashing garbage commits: it’s called git rebase -i. Just fix up the garbage commits, because surely if you have made a change non-trivial enough to require WIP commits, it can’t be trivial enough to fit in a single commit, now can it?

But git merge --squash is not the target of my ire today. No. It is GitHub, and it is the people who enforce only using the squash and merge option on pull requests.

Listen. The only reason I have ever heard for enforcing squash and merge is “it makes for a cleaner commit history”. Cleaner my foot. The only way to have a good commit history is to commit with intention and rebasing to clarify and clean up. Squashing will not get you there. Sure, your two-thousand line diff is now compressed in one commit with a terrible message like refactor backend, rather than ten commits with even worse messages like wip and done and oops. But that is still a terrible commit history, only now the terribleness is compressed in less commits.

Worse, squashing will actually delete any commits made with intention. And unless you really expect every commit to be a PR, which is patently ridiculous, you are actually removing good history and actively making it worse.

Furthermore, say you want to squash and merge and actually have a good commit message. Suppose you rewrite the entire commit message or whatever. A good commit message has appropriate line wrapping, something my editor (vim) is perfectly capable of handling properly. GitHub does not even give a whit of an indication when a line is too long. So you can’t even write a proper commit message. Ridiculous.

So what should you do? Just merge. Merge like a normal person.

git merge --no-ff

This makes a merge commit even when you could have fast-forwarded, because it explains why you are merging a certain feature.1


While I’m at it, GitHub pull requests are a disaster. As usual, the Linux Kernel is the gold standard.

When you want to merge feature into master you should run git merge feature while in the master branch. And obviously you take care of any merge conflicts in this merge. In particular, you do not “back merge” master into feature without good reason because

Merge branch 'feature'

Merge branch 'master'

is a really stupid commit history! But GitHub, especially with a lot of its automated CI/CD stuff encourages maintainers to put the responsibility of fixing conflicts on the people writing the PRs. So now the only thing they can do is rebase on top of master, and then re-test every commit because otherwise they’d be lying.


  1. If you want to fast-forward, that is also fine, but in my opinion the times you should fast-forward are precisely the times when you should rebase. Yes, a fast-forward merge and rebase are identical, but it really “belongs” with rebasing.↩︎