Merging on a Team

directions, the release rule, the revert traps, and the verify discipline

$ git log --oneline --graph -4
*   8e35098 Merge branch 'main' into feature-cart
|\
| * 5b529d9 ship auth v2 on main
* | a752b26 start the cart module
|/
* e0410a3 open the app
a back-merge on the record - real graph output

Merges have directions - team labels, not git commands. A back-merge pulls main's progress INTO your feature branch, so you integrate against fresh ground instead of a month-old base. A forward-merge delivers the finished feature INTO main - with --no-ff when the team wants a visible two-parent record of the delivery.

read it:   * a save   | the other lane   |\ lanes split   |/ lanes meet

The two directions draw one shape: main's work flows down into the feature, the feature's finished work flows up into main, and both histories stay visible behind the knots:

shape-rails
shape-cap
$ git switch -c cutout release/1.x
$ git merge main
CONFLICT (content): ... config.txt
$ git add config.txt
$ git commit
$ git switch release/1.x
$ git merge cutout
Fast-forward
resolved AND committed on the cutout; release fast-forwards (output elided)

The release rule: a release branch should never hold a half-resolved merge conflict - you ship from it. Cut a temporary integration branch FROM the release (the cutout), merge main into it, resolve and COMMIT there, verify - and if the release branch has not moved meanwhile, it simply fast-forwards to the finished merge.

$ git merge feature-login
Already up to date.
$ git revert 71e862a
[main 31b0b03] Reapply "merge the
  login feature"
the dead end and the escape (line-wrapped to fit)

Two revert traps every team hits once. First: a revert travels - revert a change on your branch and later merges deliver the cancellation to the target too; the branch looking clean does not unhappen the history. Second: revert a MERGE and the graph still remembers the branch as merged - re-merging brings nothing back ("Already up to date."). The escape is to revert the revert, then merge new work normally.

gl-range8
gl-dd8-a
gl-dd8-b
gl-dd8-c
$ git diff main~1...HEAD -- bake.txt
...
-bake_minutes=40
+bake_minutes=20
...
$ git merge f4-thick # rerere enabled + ruled before
Resolved 'menu.txt' using previous
  resolution. # wrapped
the first-parent diff + a ruling replayed

Last discipline: a clean merge is not a correct merge Before pushing a merge that matters: diff the result against EACH parent (HEAD^1 and HEAD^2 - the seat shows the first), read what it took from each side, and run the tests. On long-lived branches, rerere replays rulings you have made before (until its cache expires).