Say where each branch stands, and whose rebase fixes a failure - #11
Draft
chris-peterson wants to merge 1 commit into
Draft
Say where each branch stands, and whose rebase fixes a failure#11chris-peterson wants to merge 1 commit into
chris-peterson wants to merge 1 commit into
Conversation
A failed merge printed the whole set it was merging, because the combined `git merge` can't tell which branch caused the conflict. The usual response to that is `git fi -f <my-branch>`: replace fi with one branch, discard everyone else's integration, and meet the same conflict again the next time someone adds theirs back. Follow the failure with a second pass that can attribute it. Merging the list one branch at a time with `git merge-tree --write-tree` separates "this branch needs a rebase onto main" from "these two branches overlap", and a pairwise sweep names the actual peer rather than the whole accumulated set. It reads the object database only — no ref, no index, no working tree — so it runs after the tree is restored and disturbs nothing. Each failing branch comes back with its conflicted paths, the email of whoever last moved it — so the report says who owns the fix — and the remedy its case calls for, closing with the `git fi -r` line that takes the failing branches out temporarily. `--force` is offered nowhere, and the docs argue against it rather than merely omitting it. The list gains two per-branch markers for where a branch stands before anything is attempted: `↓N` for how far it trails the default branch, which is the precondition for the conflict and so says which branch to rebase first; and a struck-through name marked `merged` for a branch whose commits have all landed, which is spent and which the next mutation prunes. Both come from `%(ahead-behind:)` on the branch listing that already runs — the behind half for the count, the ahead half for merged-ness. The ahead half also replaces the separate `git branch -r --merged` invocation, since a branch with nothing ahead of the default branch is exactly what that reports. `--json` nests everything about a branch under the branch: `branches` becomes an array of objects carrying `name`, `ahead`, `behind`, `merged`, and `ci`, and the top-level `ci` array is gone. Parallel arrays keyed by branch name made a consumer join to answer "what is the state of this branch", and let the arrays disagree about which branches exist. Nothing consumes this output yet, so the shape changes outright rather than growing a compatible alias. The atom arrived in git 2.41.0, so the floor in PRE-02 moves there from 2.13.0. That is the price of a commit count over a bare behind flag: 2.41.0 was released 2023-06-01, and a long-support distribution below it needs a newer git installed. `--check`, which would answer "will my add land?" before attempting it, is captured as FUT-01 rather than built here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
git-fi maintains a shared
fibranch that merges everyone's in-flight feature branches together, so conflicts between them surface while both branches are still small instead of at release time. When that combined merge fails, though, it prints the whole set it was merging — git can't attribute a conflict inside one octopus merge to a single branch — and the usual response on a team isgit fi -f <my-branch>: replacefiwith just your branch and move on, discarding everyone else's integration. The conflict is still there the next time someone adds their branch back. This makesfisay which branch actually failed, who owns fixing it, and how — usually one or two rebases rather than a reset.Review guide
Start here — the attribution itself
src/readiness.tsattributeConflicts— replays the branch list one at a time ontoorigin/main, then probes each failure againstorigin/mainalone to split "needs a rebase" from "collides with a peer", and sweeps pairwise to name which peer. A failing branch is left out of the accumulation, so one bad branch doesn't condemn everything after it.src/readiness.tsmergeTree— the whole thing runs ongit merge-tree --write-tree, which merges in the object database and exits 1 on conflict. No ref, no index, no working tree, so it runs after the failed merge is cleaned up and disturbs nothing.src/merge.ts— where it hooks into theMERGE-11failure path.The report a user actually sees
src/readiness.tsrenderConflicts— each branch carries its tip author's email, so the line says who owns the fix; the report closes with agit fi -rline marked temporary.--forceis offered nowhere.One listing answers three questions
src/git.tsthe--formatstring —%(ahead-behind:)and%(authoremail:trim)ride on thegit branch -rlisting that already runs, so the behind count, merged-ness, and the author cost no extra invocation.src/git.tsmergedRemoteBranches— a branch with nothing ahead ofmainis exactly whatgit branch -r --mergedreports, so the ahead half replaces that second invocation. Worth a look: this changes the mechanism behindMERGE-07's existing prune.src/style.ts—↓12for a branch trailingmain, a struck-through name plusmergedfor one that's landed. The word rides with the strikethrough because not every terminal draws SGR 9, andmergedsupersedes the behind count rather than stacking with it.Skim
src/readiness.tsbranchJson—--jsonnow nests everything under the branch; the top-levelciarray is gone. Parallel arrays keyed by name made a consumer join to answer "what's the state of this branch", and could disagree about which branches exist. Nothing consumes this output yet.SPEC.mdMerge Readiness —READY-01..READY-07, plusFUT-01capturing--check(answer "will my add land?" before attempting it) as deferred.test/readiness.test.ts— the discriminating cases: a branch clean againstmainbut colliding with a peer is blamed on the peer, and a clean branch merged earlier in the same run isn't blamed at all.Approach & trade-offs
The git floor moves from 2.13.0 to 2.41.0 (
PRE-02,src/git.ts). That's the price of a commit count rather than a bare behind/not-behind flag:%(ahead-behind:)landed in 2.41.0, released 2023-06-01.git merge-tree --write-treeneeds only 2.38.0, so attribution isn't what sets the floor.Who that excludes: Ubuntu 22.04 ships git 2.34.1. macOS is fine either way — Apple's CLT git and Homebrew's are both well past it. The cheaper alternative is
git branch -r --contains, which keeps the 2.13.0 floor and gives a boolean instead of↓12.