Why I Prefer Regular Merge Commits Over Squash Commits
I used to think squash commits were so cool, and then I had to use them all day, every day. Here’s why you should avoid squash
“Wow, that’s so cool!”
I’ll always remember seeing my first squash commit.
When I first joined a large engineering organization with more than 200 members, the squash commits were the first thing I noticed.
To me, the consistent use of squash commits across the company screamed “professionalism” and “we know what we’re doing here!”
It took me about a month to realize that I really, really didn’t like squash commits, and I started longing for good, old-fashioned merge commits.
Comparing Squash vs. Merge Git Commits
As a refresher, the difference between a “squash commit” and a “merge commit” is that a regular “merge” includes all of the Git commits in the history of the target branch, while “squash” flattens them to one commit.
Confusingly, “squash” isn’t its own command. Instead, you can choose “squash and merge” or “squash and rebase” as an option when you’re running the git merge or git rebase commands, respectively.
By default, a pull request (PR) will be a merge commit, so after the PR is merged then the entire history of the working branch will be merged in, plus an additional commit (“Merge pull request #21 from branch…”).
On the other hand, you can set your repository to “squash and merge” by default, meaning merged PRs will result in only a single commit each, instead of bringing over all the commits from the working branch.
Why Would Anyone Use Squash Commits?
The benefit of squash commits is that you keep a “clean” Git commit history. Since we developers are famously… let’s say “precise”… then a tidy commit history sounds absolutely fantastic. It’s not.
You can see why I was impressed by the professionalism — the entire engineering organization was so dedicated to having a clean commit history that they had mandated “squash and merge” as the default!
Unfortunately, the benefits of having a clean commit history end exactly right there — the history may be clean, but my day-to-day work needed much more context than what a squashed commit could provide.
By definition, a squash commit loses information. I like to think of it as a black hole, where the information gets turned into “Hawking radiation,” which in this particular case is measured in units of developer frustration.
The Overwhelming Weakness of Squash Commits
I soon became disillusioned with squash commits for the simple reason that my job was 90% fixing bugs in old code. When I would inspect a line using Git Lens to run git blame, I would never learn everything.
Literally every git blame at the company read, “Merge pull request #237 by {my boss or coworker},” with no additional information. I couldn’t even find the topic of the PR without looking it up manually! How frustrating!
I would dutifully pull up the original PR and ticket, trying to get some sense of why this particular line of code changed, and I would have no idea. You know how a PR often changes hundreds of lines of code at once? Yeah…
I can count on one finger the number of times I needed to actually revert an entire squashed commit at once, and it was a dramatic rollback of a PR that pushed our entire roadmap back by an entire month.
The rest of the time, I’d be doing my normal work, trying to fix bugs with a deadline of “can you get this to QA by end of day?” And when I’d inspect a line, I’d have no idea why it was changed, because of the squash commits.
Why I Prefer To Not Squash My Merge Commits
Look, I would love a clean commit history, too, but the downsides are crippling to day-to-day work. While it’s great to know “this broke when fixing this other bug,” a squash commit doesn’t give me enough info.
Let’s say I know my boss changed a certain line of code 18 months ago by inspecting it with git blame. At this point, he surely has no idea why he changed it, even if he could find the time to investigate it for me.
With squash commits, I’m left with less information: I can only find out the bugfix or feature that resulted in the line being changed, not the actual reason the line was changed, and that’s just not enough to go on.
While it would be great if every line had a code comment or two, we all know that’s not how most developers work — I typically see less than 1% of code actually having any comments when I look at a new React codebase.
The reason I have no idea why the code changed is pretty straightforward; my boss wrote down the reason at the time (in the commit message), but then we decided to “squash” it away for no reason. That does not spark joy.
The Solution Is To Just Merge, Not Squash, Commits
There’s a super simple solution here, and it’s actually the default — just don’t squash. What I want to know isn’t much, but it makes all the difference:
- refactor: Was my boss “refactoring” this code to be more readable or maintainable, hopefully without affecting the actual functionality?
- chore: Was my boss doing some cleanup “chores” that shouldn’t have affected the production code, such as adding code comments or tests?
- fix: Was my boss “fixing” an identified issue, and if so what was the specific issue that was broken with this piece of code?
- feat: Was my boss implementing a new feature, such as creating a brand-new component with user-facing functionality?
Did you pick up on the fact that these are Conventional Commits (also called “semantic commits”), which are best paired with atomic commits?
The reason I became so disillusioned with the company is that there was a great culture around commit messages, but a terrible one around PRs.
Since we had super-long JIRA tickets, there wasn’t a great reason to write much in a PR, but then we threw away all of our context by squashing.
The result was we would spend literally hours trying to fix bugs because no one remembered what any given piece of code was supposed to do.
So, at my current company, I make dozens of commits a day, and I leave them all in the history when I merge my PRs. It may be a little messy, but it’s better for my sanity, as well as for my GitHub contribution graph.
Happy coding!
P.S. If you liked this hot take on Git best practices, then you’ll love me trying to convince you to write 200-character commit messages, right? Read this:
Dr. Derek Austin is the author of Career Programming: How You Can Become a Successful 6-Figure Programmer in 6 Months, now available on Amazon.






