Visualizing the implementation of Github's merge methods.
- merge
- squash (and merge with fast forward)
- rebase (and merge with fast forward)
- merge
- mergeff (mergeff-pr on top of mergeff)
- squash
- squashff (squashff-pr on top of squashff)
- rebase
- rebaseff (rebaseff-pr on top of rebaseff)
-
more often than not, squash and rebase are preferred for a simple/r history, but the same effect can be achieved by
- squash-like:
git log --first-parent
which hides the PR commits and only keeps the "Merge pull request #X from SOURCE" commit - rebase-like:
git log --no-merges
which hides the "Merge pull request #X from SOURCE" commit and only keeps the PR commits
- squash-like:
-
rebase will mean there's no merge commit and thus no way to logically and visually group related-commits. It will be impossible to know the context of the changes.
-
rebase will mean there's no merge commit and thus no way to revert the entire group of related-commits. It will be impossible to undo a PR.
-
rebase will mean there's no merge commit and thus no reference to the PR number. It will be impossible to know the context of the changes.
-
rebase will mean you lose the GPG signature (squash will retain it). It will be impossible to verify source.
-
rebase will mean
git log
becomes the same asgit log --no-merges
, and that you lose the ability togit log --first-parent
. It will be impossible to hide "noise". -
squash will mean everything is "noise". More often that not, a PR will contain "noise" (e.g. lint, whitespace, typo) fixes, along the core changeset. While many will complain about many "noisy" commits, you can distinguish between signal and noise. Squashing signal and noise though, gives you noise. If you use
git revert
orgit bisect
, then don't squash. If you don'tgit revert
, then start. If you don'tgit bisect
, then start. -
squash is not simple at all. See nodejs requirements for using the squash merge.
-
more here by @myst729 , including merge-conflicts https://myst729.github.io/posts/2019/on-merging-pull-requests/
-
ultimately the merging strategy should NOT be a per-PR choice, but a per-repo choice, and it should be "rebase WITHOUT fast-forward preserving GPG signature", in other words a local
git fetch && git rebase origin/master
.
The beauty of a git history does NOT come from a visual linear history.
The beauty of a git history comes from
- being able to read it: ideally one "merge bubble" at a time, meaning rebase before you merge WITHOUT fast-forward
- being able to use it:
git blame
a line,git revert
a small commit,git bisect
down to a small commit
And in the light of the above,
the merge strategy is the only one worry free, though not ideal either