Where structure comes from
Every command that selects a stack asks one question first: which source describes this branch?
adopted into g2g's store → g2g's own graphtracked by Graphite → Graphiteneither → refused, with the remedyAdoption wins because recording an edge is you saying you want g2g to own the branch. Graphite is the fallback for branches g2g has not adopted.
Per branch, every time, never stored
Section titled “Per branch, every time, never stored”The answer is worked out per branch, every time, and never stored. Moving a
branch between sources is therefore just g2g track or g2g untrack, in
either direction, and there is no ownership record to go stale.
It is per branch rather than per stack because a stack can legitimately span
sources: main, then a branch Graphite tracks, then one adopted into g2g
above it. A rule for the whole stack would have to give one of them the wrong
answer. It is never stored because a stored owner goes stale through actions
g2g never sees, such as someone running gt track on a branch that joins two
trees.
What each source is good for
Section titled “What each source is good for”| Source | Expresses | Unpublished branches | Trees | Shared |
|---|---|---|---|---|
| g2g’s store | intent | yes | yes | no |
| Graphite | intent | yes | yes | no |
| pull request bases | effect | no | yes | yes |
g2g’s store and Graphite say what was meant. Pull request bases say what GitHub will do on merge. That is not a weaker authority, it is authority over a different question, and both answers are worth having.
Graphite is never a requirement
Section titled “Graphite is never a requirement”push, submit and github link work on a stack g2g owns, with no Graphite
installed. And g2g will not run Graphite in a repository that does not
already use it. Graphite’s discovery creates state, so being asked whether it
applies must not be what enrols you. In such a repository g2g stays local. See
Graphite for keeping the two records in step where
you do use it.
Authority governs changes, not reading
Section titled “Authority governs changes, not reading”Reading composes across sources: a branch can sit in g2g’s graph, be tracked by Graphite, and appear in a GitHub stack all at once, and nothing here removes it from any of them. Authority is not exclusive.
restack is the exception, deliberately. It needs a fork point, which only
g2g’s own store records, so it refuses a Graphite-owned branch and says to
g2g track it first. land likewise needs the stack in g2g’s own graph,
because it replays and forgets there. See Land.
--from pins the source
Section titled “--from pins the source”g2g status --from graphite # Graphite's record, drawn in g2g's formatg2g github status --from graphite # and its pull requests, as Graphite groups themg2g push --from g2gOnce a branch is adopted there is otherwise no way to ask Graphite what it thinks of it, and comparing the two views is what you want before reconciling them. Nothing is recorded.
status --from offers only the offline records, g2g and graphite. It draws
shape and no state: needing a restack or having moved off a parent is worked
out from recorded fork points, which only g2g’s store has, so another record
can say where branches sit but not whether their contents have drifted.
Pull request bases, only when asked
Section titled “Pull request bases, only when asked”Pull request bases are a third source, github, read only when you name it:
g2g github status --from github --scope stackIt shows a repository’s published branches as a tree with nothing recorded
locally, and says what GitHub will merge rather than what you intended. It is
never consulted by precedence, because reading a base invokes gh, and push
must never do that.
Asking for it makes its two limits an informed reading rather than a silent one:
- It describes published branches only. No pull request, no edge.
- GitHub retargets a child when its base branch is deleted on merge, so right after a parent lands its children point at the trunk. It is never wrong about what a merge will do, and no longer a record of what the stack was.
g2g github adopt records what it describes. See
GitHub.
GitHub’s native stack is not a source at all. Nothing defines a stack by editing it: branches and bases are edited, and the native stack is written from them.
Trunks are never guessed
Section titled “Trunks are never guessed”A trunk is never inferred from a branch’s name.
- On a Graphite-described stack, g2g infers the only Graphite-declared trunk on
the selected ancestry and shows it prominently. If that ancestry has several
declared trunks, it fails closed and requires
--trunk <branch>, and the branch you name must be both declared by Graphite and an ancestor of the selected branch. - A g2g-owned path has exactly one root, so
--trunkcan only confirm it. Naming any other branch is refused rather than ignored, because silently using a different base than the one asked for is how a stack gets pushed at the wrong thing.
Further reading
Section titled “Further reading”design-docs/source-resolution.md records the reasoning in full.