Skip to content

Compatibility and storage

Recording and maintaining a stack’s structure needs only Git. Graphite and GitHub are integrations: g2g talks to them only when a command reaches for them, and the versions below matter only then.

When Graphite is selected as a source, g2g uses Graphite CLI 1.8.6 as its tested compact-display baseline. Compatible patch and minor versions continue with a warning on stderr, while an unsupported major version or a changed display grammar fails safely.

g2g reaches Graphite only through its supported, non-interactive CLI. It never reads Graphite’s private metadata database or configuration. Discovery is read-only; g2g graphite mirror is the one command that writes Graphite, through gt track and gt untrack, gated on the same version check.

g2g will not run Graphite in a repository that does not already use it, because Graphite’s discovery creates state, and being asked whether Graphite applies must not be what enrols you. In such a repository g2g stays local. See Sources.

The contract g2g holds Graphite to is pinned in design-docs/graphite-cli-contract.md.

GitHub projection requires a compatible gh with the relevant stack command: gh stack link for github link and gh stack unstack for github unlink. Every command that reads or writes a pull request invokes gh; apart from submit and land, those commands live under g2g github. push never invokes it.

The branch forest g2g records is stored at:

Terminal window
$(git rev-parse --path-format=absolute --git-common-dir)/g2g/graph.json

--path-format=absolute matters: the bare --git-common-dir is relative to the current directory, so it returns .git from the repository root and ../../.git from a subdirectory.

Because it lives in the Git common directory:

  • Linked worktrees share it.
  • It never appears in a diff or dirties a checkout.
  • It is neither pushed nor shared between clones. A fresh clone starts empty, which matches the unpublished branches those edges describe: they do not survive a clone either.

To pick up a stack someone else published in a fresh clone, adopt it from its pull requests; see Adopting a published stack.

Writes are a temporary file in the same directory plus a rename, so a concurrent reader sees either the old graph or the new one, never a partial write. Nothing is written without an explicit --apply.

The store records each branch’s parent and its fork point, the parent’s tip when the edge was written. The fork point is what tells restack which commits are the branch’s own, and it cannot be worked out after the fact once a merged parent’s branch has been deleted. A branch’s own tip is deliberately not stored, so an ordinary commit never looks like a change to the graph.

The graph carries its own storeSchemaVersion, separate from the --json output’s schemaVersion (see Output). They evolve separately. An unrecognised store version fails closed rather than being rewritten.

See design-docs/g2g-owned-graphs.md for the model, the storage decisions, and what is deliberately left out.