You Should Squash Merge to main
yeah, I said it.
Every so often I’ll see a meme on Twitter like:
and it makes me so mad. For good reason! OSS project repositories that support merge commits to main are usually littered with useless comments like: “Merge change from $USER, $PR”. It makes the commit history on main utterly useless and you get to check the various feature branches in a never ending snake of commits to find out what the hell changed.
You should squash merge.
Here’s why you should squash-merge:
-
Every single commit on main should be releasable. A chain of commits that are merged in one go are not necessarily releasable.
-
The commit messages in feature branches are usually uninteresting, and that’s a good thing. It is absolutely OK for your commit log to look like:
- $TICKET: Prepare for new service by creating configuration files and code skeleton.
- Fix missing environment variable
- checkpoint for EOD
- finished!
as long as your merged commit on main is:
- $TICKET: Prepare for new service by creating configuration files and code skeleton.
I believe that advocates for keeping the commit history of a branch during merges think that you should re-write your feature branch commits to be more meaningful before actually merging. What a waste of time!
-
A messy feature branch history is good, actually. Messy branch history allows you to push to remote at any time without really thinking about it. Replication helps when you leave your laptop on the train, or to quickly share the state of your work with a coworker. After it’s on the remote you should try not to force push it, especially if you’ve shared it.
-
You don’t lose anything interesting in squash merge. It doesn’t matter what the commit was where you forked from main. It only matters what the difference between main and your branch is when you merge. You can most cleanly see that change by comparing sequential commits to main that have nice clear messages.
-
Merge commit messages are useless out-of-the-box. Why write the same commit message twice - you have it somewhere in your feature branch and then again (hopefully) in your merge commit.
-
You only need to view the commit log of main to understand what changed when. This is what you care about when you release software.
My actual favorite solution to this problem is to use the Gerrit workflow that guarantees any merged piece of code is a single “change set” that’s merged atomically. Squash Merge is the closest thing Github provides in its UI, so do that.