Output
Every command renders one semantic view. The human-readable preview is the
default, and --json and --porcelain are alternative renderers over exactly
the facts the graph shows, so nothing has to parse decorated terminal text.
Global flags
Section titled “Global flags”These are root flags, accepted by every command:
| Flag | Does |
|---|---|
--json |
emit one JSON document instead of the human-readable preview |
--porcelain |
emit stable tab-separated records instead of the human-readable preview |
--no-links |
do not attach hyperlinks to pull request numbers |
--debug |
write safe diagnostic events to stderr |
--timeout <duration> |
the maximum duration for each phase, discovery and mutation separately |
Colour and hyperlinks
Section titled “Colour and hyperlinks”Colour is enabled only for an interactive terminal. It is disabled for
redirected output, CI, NO_COLOR, and TERM=dumb, so the plain graph is
deterministic for scripts. In colour output, headers, trunks, branches, pull
request numbers, unresolved state, and success use distinct, restrained roles;
the renderer keeps plan data separate from the ANSI decoration.
Pull request numbers are hyperlinks where the terminal supports them. The text
is unchanged, so #42 reads as #42 either way and a terminal without OSC 8
support loses nothing. Links follow the same interactive-terminal rule as
colour but deliberately ignore NO_COLOR, which asks for output without colour,
and a hyperlink is not colour. --no-links turns them off; --json and
--porcelain never emit them.
A number points at GitHub when GitHub reported an address for it. That address
came back from the API rather than being assembled, so it cannot be wrong about
the repository. Otherwise it points at Graphite’s view of the same pull request
(https://app.graphite.com/github/pr/<owner>/<name>/<number>), which a
repository that does not use Graphite never produces.
Copyable commands
Section titled “Copyable commands”Nothing but whitespace ever shares the line holding a copyable command: no prompt character, border, or annotation. A loose, wrapped, or whole-line selection can only pick up spaces, which a shell ignores. In colour output the highlight is padded a few columns past the command to widen the click target, and every highlighted command, on its own line or inside a sentence, carries a column of background on each side. Those columns are painted rather than written: without colour the text reads exactly as it was typed.
A hint that names a command mid-sentence draws it with the same highlight, so
you can see where it starts and ends without reading the prose around it. Which
words are a command is recorded when the sentence is written rather than found
by a pattern afterwards, so what is highlighted is exactly what can be copied
and run. Plain output, --json, and --porcelain carry the sentences
unchanged.
Machine-readable output
Section titled “Machine-readable output”--json and --porcelain both suppress colour and every human-facing line,
emitting only the document. They are mutually exclusive, and the default stays
the human-readable preview.
# One JSON object with a schemaVersion, the operation, the trunk, each# branch's pull request and state, and the validated command when one applies.g2g github status --json
# Stable tab-separated records, each led by its type:# target <branch> <source># trunk <branch># branch <name> <pr> <state> <severity> <url> <target?> <parent?># blocked <reason># repair <reason># way <command> <effect># command <argv>...# step <n> <command> <effect># note <severity> <text># comment <pr> <branch> <action> <reason>g2g github link --porcelainFields
Section titled “Fields”operationis the command’s path as you would type it afterg2g:status,pull,github link,graphite adopt.parentis populated byg2g status, where order alone cannot express structure once a graph forks. The linear commands leave it empty, and their order still holds. In porcelain it is appended after the fields that shipped before it, so an existing reader keeps working.blockedis reported alongsidecommand, not instead of it, so a consumer can see the destination and decide for itself. Checkblockedbefore acting oncommand.repairis what to do aboutblocked, with each way out carried as a command and what running it achieves, so a consumer does not have to find the command inside a sentence. A way out with nocommandis a whole answer that is not a thing to run, such as “fetch and reconcile first”, rather than a step with a field missing. A refusal that nothing here fixes carries norepairat all. It is also reported where nothing is blocked and there is still something to do: a branch no source describes is a state, not a refusal. See When a command refuses.sequenceis the ordered recipe for a command whose work is several steps (land,create).commentscarries each pull request comment agithub commentrun writes, with its body in--json. Porcelain says what happens to each comment but not its text, since a body is many lines.
pull --prune refuses both formats, because it produces two reports and those
formats are one document.
Schema versions
Section titled “Schema versions”schemaVersion is bumped when a field changes meaning or disappears; adding a
field is not a breaking change.
- Schema 2 narrowed
blockedto the reason alone. It used to carry the label a person is shown in front of it, which differed between commands; that label is the renderer’s now. - Schema 3 made
operationthe command’s path, because the commands moved:graphbecamestatus,syncbecamepull, and what reads or writes GitHub isgithub link,github statusand so on. A consumer switching on the old names would have read the offlinestatusas the pull request one.
The JSON schemaVersion is separate from the storeSchemaVersion of g2g’s
graph; see Compatibility and storage.
Diagnostics
Section titled “Diagnostics”g2g --debug github link --branch feature/top--debug is a root flag and may appear before or after any command. Its output
goes only to stderr, so stdout keeps the normal preview. It does not change
discovery, timeouts, checkout behaviour, or mutations.
Its records summarise supported Graphite discovery, the selected path, batched
GitHub pull request facts for github link (including native stack number and
position), or the selected remote and the atomic, leased Git arguments for
push, plus plan and revalidation decisions and bounded subprocess status. It
never logs environment values, credentials, auth headers, cookies, or GraphQL
query payloads.
Timeouts
Section titled “Timeouts”g2g --timeout 3m submit --spec "$spec_dir/submission.json" --applyDiscovery and mutation are bounded separately:
| Phase | Default budget |
|---|---|
| discovery and revalidation | 45 seconds |
| mutation | 60 seconds plus 30 per selected branch |
mutation, for land |
60 seconds plus 180 per selected branch, because it waits on GitHub between its calls |
The mutation budget is taken fresh rather than from whatever discovery left
over, so a slow read can never cancel a push or a pull request creation
halfway. The root --timeout flag replaces both ceilings, for a slow network
or a deep stack.
A mutation that does expire says so explicitly and states what may already
have happened, because an interrupted submit can leave refs pushed and some
pull requests created. Re-running it with the same spec is safe and creates
only what is missing.