Graphite muscle memory, backed by GitHub's native stacks.
gtstack installs a gt command that translates the Graphite CLI commands
you already know into GitHub's official gh stack commands and
plain Git operations.
It is intentionally a thin compatibility shim. gh stack remains the source
of truth for stack state; gtstack has no backend, metadata format, or config
of its own.
Important
gtstack is early software. It currently supports linear stacks only and
targets gh-stack v0.1.0, state schema v1. When an operation cannot
be translated safely, it stops with an actionable error instead of guessing.
- Git
- GitHub CLI (
gh), authenticated with GitHub - The
github/gh-stackextension - Go 1.23 or newer to build from source
Install the extension:
gh extension install github/gh-stackInstall gt with Homebrew (macOS). The fully qualified name taps
hSATAC/toybox for you:
brew install hSATAC/toybox/gtstackOr install it with Go:
go install github.com/hSATAC/gtstack/cmd/gt@latestOr build from source and put gt on your PATH:
git clone https://github.com/hSATAC/gtstack.git
cd gtstack
mkdir -p bin
go build -o bin/gt ./cmd/gt
export PATH="$PWD/bin:$PATH"Linux builds are attached to each release as tar.gz archives.
gtstack deliberately uses the same binary name as Graphite. If Graphite is
still installed, use type -a gt to see which binary your shell will run.
You can distinguish them with:
$ gt --version
gt 0.1.0 (gh-stack shim)# Start a stack and commit the first layer
gt create -am "Add the API client"
# Add another layer
gt create -am "Use the API client"
# Inspect the stack
gt log
# Create or update the native GitHub stack
gt submit --stackEach gt invocation operates on the same stack state as gh stack, so you can
mix the two CLIs whenever you need a native command:
gt log
gh stack modify
gt submit --stackgh stack alias gt only forwards arguments unchanged, but the two CLIs do not
have the same command surface. Some commands have different names:
gt create → gh stack add
gt log → gh stack view
gt restack → gh stack rebase
Others have actively conflicting meanings. Graphite's gt modify amends the
current branch and restacks its descendants, while gh stack modify opens a
TUI for restructuring the stack. gtstack translates the intent instead of
blindly forwarding the command.
| Graphite command | What gtstack runs |
|---|---|
gt create / gt c |
gh stack init for a new stack, or gh stack add at the top of an existing stack |
gt modify / gt m |
git commit [--amend], then gh stack rebase --upstack --no-trunk |
gt submit / gt s / gt ss |
gh stack submit --auto (-e opens the editor) |
gt sync |
gh stack sync (-d maps to --prune) |
gt restack |
gh stack rebase (-d/-u map to --downstack/--upstack) |
gt continue / gt abort |
Continue or abort the paused gh stack rebase or gh stack modify |
gt checkout / gt co |
gh stack checkout, gh stack switch, or git checkout, depending on the target |
gt get <pr> |
gh stack checkout <pr> |
gt log / gt ls / gt ll |
gh stack view, gh stack view --short, or git log --graph |
gt up, down, top, bottom, trunk |
The corresponding gh stack navigation command |
gt merge |
gh stack merge |
gt switch |
gh stack switch |
gt pr |
gh pr view --web |
gt init |
Nothing. Explains that gh stack has no repository-level init |
Run gt <command> --help for the supported flags. Unknown flags are rejected
rather than silently dropped.
gh stack represents a stack as a flat ordered list. gtstack therefore does
not support forks:
gt createmust run from the top of the current stack.- If a branch belongs to more than one stack,
gtstackstops and asks you to usegh stackdirectly.
Graphite's gt submit submits the current branch and its downstack branches.
gh stack submit covers the entire stack, so gtstack does too. Pass -e to
open the submit editor and deselect branches.
gh stack submit opens that editor whenever it has a terminal. Graphite's
submit does not, so gt submit passes --auto and skips it. New PRs are
created as drafts; pass -p to mark them ready for review.
Note
-p maps to --open, which marks new and existing PRs ready for review.
It will publish a PR you had deliberately left as a draft, so gt submit
never passes it for you.
gh stack has no equivalent of Graphite's amend operation. gtstack commits
or amends with Git, then asks gh stack to rebase the upstack branches. If the
current branch has no commits of its own, it creates a commit rather than
rewriting its parent's commit.
gt co without an argument opens gh stack switch, which lists branches in
the current stack rather than every tracked branch. Trunk and untracked local
branches are checked out directly with Git.
Before running each native operation, gtstack prints the exact command to
stderr:
$ git add -A
$ gh stack add 07-31-add_the_login_form
$ git commit -m 'Add the login form'This keeps stdout clean for pipelines such as:
gt log --json | jqColor is disabled when stderr is not a terminal or when NO_COLOR is set.
gtstack is a workflow bridge, not a complete reimplementation of Graphite.
Each command below stops with the reason and the nearest git or gh stack
alternative; run it to see the advice for that command.
None of these are merely unfinished. They are grouped by what blocks the translation.
fold move reorder rename delete
gh stack can perform these, but only inside an interactive editor. No flag
drives them, so there is nothing for a one-line gt command to call.
absorb split squash pop revert undo freeze unfreeze
The operation does not exist in the gh stack model. Most of them name a Git
recipe instead — gt squash points at git reset --soft <parent>, for example.
freeze and unfreeze have no counterpart at all.
track untrack unlink
Graphite tracks and untracks one branch. gh stack works a whole stack at a
time: gh stack init adopts a list of branches into a new stack, and
gh stack unstack drops an entire stack. Translating between them would
silently widen what you asked for, so gt refuses instead.
aliases auth changelog children config dash
demo docs feedback guide info parent
gh itself, GitHub, or nothing at all handles these. gt has no configuration
of its own, so gt config points at gh.
If github/gh-stack is missing, gtstack offers to install it interactively:
gt: the gh stack extension is not installed. Install it now? [Y/n]
In a non-interactive environment it never installs software automatically; it prints the installation command and exits instead.
To decide whether gt create should initialize or extend a stack, gtstack
reads the state written by gh stack at .git/gh-stack. It refuses to run
against an unknown schema version so that a future gh-stack update cannot
silently corrupt a stack.