Squash and merge is a common practice with Git. It’s biggest and most obvious benefit is arguably a cleaner commit history that is something like…
a Created project
b Added a feature
c Add another feature
d etc...
…whereas simply merging commits invariably can lead to something like…
a Created project
b Added directory structure
c Added a feature
d Fixed whitespacing
e Added test
f Fixed test
g etc…
But there is a downside. Commits are the building blocks that Git uses to identify atomic changes. Squashing them lowers the resolution of what Git is able to see, and by extension, prevents atomic commits from being portable across branches.
While I was aware of this trade off on some level, I recently came across a great example that illustrates the downside.
Scenario
Master has branch A, which has a sub-branch B. While I don’t make a habit of sub-branching, it has been useful on occasion when I need to isolate unrelated changes that depend on the changes of some unmerged branch.
(Master) a-b-c
\
a-b-c-d-e-f (Branch A)
\
a-b-c-d-e-f-g-h (Branch B)
Merge
Commits from Branch A are merged into Master.
(Master) a-b-c-d-e-f
\
a-b-c-d-e-f-g-h (Branch B)
When commits from Branch B are merged into Master, there is no inherent conflict because Git knows that the commits “d”,“e”, and “f” in Branch B are the same commits that have already been merged.
(Master) a-b-c-d-e-f-g-h
Squash and Merge
Commits from Branch A are squashed and then merged into Master.
The changes from “d”,“e”, and “f” are now in the newly squashed commit “def”. Git no longer knows that these are the same changes so now there is a conflict with Branch B.
(Master) a-b-c-def!
\
a-b-c-d!-e!-f!-g!-h! (Branch B)
So now before we can merge Branch B, we have to create a new commit that resolves this conflict.
(Master) a-b-c-dfh
\
a-b-c-d-e-g-h-i (Branch B)
Only then can we squash and merge branch B.
(Master) a-b-c-dfh-eghi
This isn’t to advocate never using squash and merge, but to illustrate how squash and merge is really a blunt instrument. Blunt instruments are still very useful, but they should be used carefully and with consideration. If the goal is a cleaner commit history, most projects are better served by manually rebasing commits before merging branches.