Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gtstack

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.

Quick start

Requirements

Install the extension:

gh extension install github/gh-stack

Install gt with Homebrew (macOS). The fully qualified name taps hSATAC/toybox for you:

brew install hSATAC/toybox/gtstack

Or install it with Go:

go install github.com/hSATAC/gtstack/cmd/gt@latest

Or 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)

Use it like Graphite

# 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 --stack

Each 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 --stack

Why not just alias gh stack to gt?

gh 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.

Command mapping

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.

Important differences from Graphite

Linear stacks only

gh stack represents a stack as a flat ordered list. gtstack therefore does not support forks:

  • gt create must run from the top of the current stack.
  • If a branch belongs to more than one stack, gtstack stops and asks you to use gh stack directly.

gt submit covers the whole stack

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.

gt modify is implemented with Git

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.

Checkout is stack-scoped

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.

Transparent by default

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 | jq

Color is disabled when stderr is not a terminal or when NO_COLOR is set.

Unsupported Graphite commands

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.

Available only in the gh stack modify TUI

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.

gh stack has no equivalent

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.

The scope does not match

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.

Not a stack operation

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.

Extension and state compatibility

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.

About

Graphite CLI muscle memory, backed by GitHub's native gh stack

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages