To add to the "Useless uses of squash merge": Git 2.29 (Q4 2020) illustrates the traps with merge --squash
:
See commit 087c616, commit 409f066, commit 5065ce4 (20 Sep 2020) by brian m. carlson (bk2204
).
(Merged by Junio C Hamano -- gitster
-- in commit c5a8f1e, 29 Sep 2020)
docs
: explain why squash merges are broken with long-running branches
Signed-off-by: brian m. carlson
In many projects, squash merges are commonly used, primarily to keep a tidy history in the face of developers who do not use logically independent, bisectable commits.
As common as this is, this tends to cause significant problems when squash merges are used to merge long-running branches due to the lack of any new merge bases.
Even very experienced developers may make this mistake, so let's add a FAQ entry explaining why this is problematic and explaining that regular merge commits should be used to merge two long-running branches.
gitfaq
now includes in its man page:
Merging and Rebasing
What kinds of problems can occur when merging long-lived branches with squash merges?
In general, there are a variety of problems that can occur when using squash
merges to merge two branches multiple times.
These can include seeing extra
commits in git log
output, with a GUI, or when using the ...
notation to
express a range, as well as the possibility of needing to re-resolve conflicts
again and again.
When Git does a normal merge between two branches, it considers exactly three
points: the two branches and a third commit, called the merge base, which is
usually the common ancestor of the commits.
The result of the merge is the sum
of the changes between the merge base and each head.
When you merge two
branches with a regular merge commit, this results in a new commit which will
end up as a merge base when they're merged again, because there is now a new
common ancestor.
Git doesn't have to consider changes that occurred before the
merge base, so you don't have to re-resolve any conflicts you resolved before.
When you perform a squash merge, a merge commit isn't created; instead, the
changes from one side are applied as a regular commit to the other side.
This means that the merge base for these branches won't have changed, and so when Git
goes to perform its next merge, it considers all of the changes that it
considered the last time plus the new changes.
That means any conflicts may need to be re-resolved.
Similarly, anything using the ...
notation in git diff
, git log
, or a GUI will result in showing all of the changes since the original merge base.
As a consequence, if you want to merge two long-lived branches repeatedly, it's
best to always use a regular merge commit.
--squash
will not really merge the branch, but will create a single commit out of it (which is then merged). Reading the manpage also suggests that no commit is made aftergit merge --squash
– Custodian