11

Some people like git merge --squash due to the reason as follows:

Squashing to a single commit gives you an opportunity to clean up messy WIP commits and provide a good rationale for the changes your are merging.

https://coderwall.com/p/qkrmjq/git-merge-squash

However, I think there is some downside which exceeds the merit of producing a clean history.

  1. git merge --squash produces a non-merge commit. Therefore, Git will not recognize that the commit you are merging from as the merge base. This leads to unwanted merge result when 1) change A to B on branch X, 2) git merge --squash from branch X to branch Y, and 3) change B to A (revert) on branch X, and 4) merge X into Y. enter image description here After step 4, on branch Y, the change from A to B is NOT reverted. Here, this is 3-way merge, so a diff from branch X to merge base and another diff from branch Y to merge base are compared. The former one includes no change, and the latter ones include change from A to B, so the merge result include the change from A to B.

  2. Commit author is overridden, which discards the contribution. git merge --squash produces a new commit with the name who did git merge --squash. Of course, the commit content is from the original commits. This sounds like stealing the contribution. This became a problem in https://github.com/Microsoft/winfile/pull/42#issuecomment-380681627

What are the proper use cases of git merge --squash?

Tomoyuki Aota
  • 867
  • 9
  • 18
  • This post hovers around similar pros and cons: https://www.reddit.com/r/git/comments/9g0kjv/what_are_the_pros_or_cons_of_squashing_before/ – nitishagar Jul 22 '19 at 11:32

2 Answers2

6

What are the proper use cases of git merge --squash?

  1. If the project has a policy of not allowing merge commits on its master branch anyway, then the fact a non-merge commit is created is not a problem (it's exactly what you'd want anyway).

    If you don't plan to use the Y branch again after the merge (e.g. because Y is a short-lived feature branch and the feature is merged to X now) then it's irrelevant that a future merge from Y has the "wrong" merge-base. You're not going to do any future merges from Y anyway.

    Or if you rebase branch Y on X after the merge, then future merges from Y will have the right merge-base.

  2. If all the commits on the branch are by the same author, then the second problem doesn't exist either.

So it might not be useful in all cases, but there definitely are cases where it's perfectly fine to use. The most obvious one is for a local branch where WIP commits are made, before pushing them somewhere other devs can see. All the messy WIP commits on branch Y are by the same author, and nobody else is ever going to see branch Y so it's fine to rebase it on X after the merge, or to just throw Y away completely if even you aren't interested in the WIP history.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • But why not just squash the 'dirty' commits and merge the (now-squashed) branch? A decent developer should be breaking a feature into multiple steps, to document the development and to allow meaningful review (e.g. by not combining development work with the necessary refactoring) and this gets lost if the whole branch is squashed. – HappyDog Dec 11 '22 at 23:57
  • 1
    You're assuming the feature is complex enough to take multiple steps. Maybe you add a unit test , fix a bug, and add another unit test. Is there really any point keeping three separate commits after merging? I'd probably squash them, but I don't think that means I'm not a "decent developer". For larger feature branches, sure, the history can be useful, but that's not the only use of git branches. – Jonathan Wakely Dec 13 '22 at 08:33
  • I assumed nothing, and I would never make a hard rule that doesn't have exceptions. However, this is a definite code smell. If those are three separate things, then they should be documented separately and show up as three separate commits. If they are three parts of the same issue I would probably have committed them in one go, but if you missed that boat, it might be a reason to squash them in the branch, so long as you give an appropriate commit message, and not some auto-generated mess. Either way, that should be done prior to review, not as part of the merge. – HappyDog Dec 14 '22 at 09:42
4

The example seems intentionally designed to demonstrate the downside. If squash-merge is suitable for Branch X, Step 3 and 4 could have been git merge BranchX -n && git commit --amend, or git checkout BranchA && git reset HEAD^ --hard && git merge BranchX --squash && git commit instead, as if BranchX is squash-merged instead of being merged twice.

The messy WIP commits are usually on a local temporary topic branch. The author of these commits is usually the same person who's going to perform squash-merge. These commits are created in a more casual way as drafts, and later squash-merge can convert them into a single elegant commit as if it's carefully created on the target branch.

Sometimes, in order to maintain a linear history, people may squash-merge one formal branch to another instead of performing a true merge. The squashed commits are created by different authors. It's possible that the contribution might be stolen. But in practice, the original branch and commit hashes with commit messages are kept in the message of the new commit by convention, and the merged branch is also preserved, so that people learn where the squash-merge commit comes from and are able to view the original commits.

ElpieKay
  • 27,194
  • 6
  • 32
  • 53