mcpField
P
pr-stack

pr-stack

github.com/paulnsorensenDevelopment141 installsUpdated 1d ago
Repository

About pr-stack

A skill for managing stacked branches and their pull requests through whichever supported tool is already configured for the repository: Graphite, git-town, or GitHub gh stack. It detects the available setup and guides stack creation, synchronization, submission, and conflict recovery without emulating the workflow with plain Git.

Key features

  1. 01Detect configured stack tooling
  2. 02Create and inspect branch stacks
  3. 03Sync and submit stacked pull requests
  4. 04Recover conflicts with tool-specific commands
  5. 05Compare workflows across three tools

Use cases

  1. 01Maintain a chain of dependent pull requests
  2. 02Restack branches after trunk changes
  3. 03Submit or update a complete stack
  4. 04Recover from a stack rebase conflict

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/paulnsorensen/skillz-that-grillz --skill pr-stack

After installing, type/pr-stackin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

evals/
evals.json
references/
gh-stack.md
git-town.md
gt.md

Details

From the project README

pr-stack

Stacked branches: a chain of small branches each opening one PR, kept in order across rebases and pushed as a group.

Three tools implement this workflow today. They share the same mental model but live in different ecosystems:

  • Graphite (gt) — third-party CLI, mature, requires a Graphite account (gt auth). Stack metadata lives in .git/.graphite_repo_config.
  • git-town (git town) — third-party CLI, mature, no account and forge-agnostic (GitHub / GitLab / Gitea / Bitbucket / Forgejo / Azure DevOps). Branch lineage lives in local git config (git-town-branch.<name>.parent), so there's nothing to sign up for.
  • GitHub gh stack — first-party gh extension (github/gh-stack), private preview as of 2026-05; repos must be allow-listed via gh.io/stacksbeta. Stack metadata lives in .git/gh-stack. Uses standard gh auth login — no third-party account.

This skill picks whichever one the user has and drives it. It does not emulate stacking with plain git.

Detection — run before anything else

# gt available?
command -v gt >/dev/null 2>&1 && gt --version >/dev/null 2>&1

# gt initialized in this repo?
test -f "$(git rev-parse --git-dir)/.graphite_repo_config"

# gh stack extension installed?
# (gh extension list output is TAB-separated: <short-name>\t<owner/repo>\t<version>)
# Guard with `command -v gh` so the probe stays quiet when gh itself is missing
# — `2>/dev/null` on the pipeline doesn't catch the shell's own "command not
# found" message.
command -v gh >/dev/null 2>&1 \
  && gh extension list 2>/dev/null | awk -F '\t' '$2 == "github/gh-stack"' | grep -q .

# git-town available?
command -v git-town >/dev/null 2>&1 && git town --version >/dev/null 2>&1

# git-town configured for this repo? (non-empty trunk = set up)
git config --local --get git-town.main-branch >/dev/null 2>&1

Pick the tool the repo is already set up for. A tool counts as usable here when it's installed and configured for this repo:

ToolInstalled probeConfigured-for-repo probe
gtcommand -v gt.git/.graphite_repo_config exists
git towncommand -v git-towngit config --local --get git-town.main-branch non-empty
gh stackgh extension list has github/gh-stackno preflight — detected lazily when a remote op exits 4

Then:

  • Exactly one usable → use it; read that tool's reference.
  • More than one usable → prefer gt (GA, mature, and the repo may already track a stack), then git town (GA, no account, forge-agnostic), then gh stack (first-party but private preview). Tell the user which others are present and offer to switch.
  • Installed but not configured → offer the one-time setup (gt init, or git config --local git-town.main-branch <trunk> — your trunk name, e.g. main / master; gh stack needs no repo init) and proceed.
  • None usable → stop. Don't reach for git push chains. See "None installed" below.

Run the probes every invocation — the user's environment can change between sessions.

None installed

If detection finds none of gt, git town, or the gh stack extension, surface this verbatim and stop:

Stacked-PR tooling isn't available on this machine / for this repo. Install one of:

  • Graphite CLI — brew install withgraphite/tap/graphite (or npm install -g @withgraphite/graphite-cli@stable), then gt auth --token <token from https://app.graphite.com/activate> and gt init inside this repo.
  • git-town — brew install git-town (or choco / scoop on Windows), then git config --local git-town.main-branch <trunk> (your trunk name, e.g. main / master; or the git town config setup wizard) inside this repo, plus either git config --local git-town.github-connector gh (reuse your gh auth) or a git-town.github-token PAT. Works on GitHub, GitLab, Gitea, and more.
  • GitHub native gh stack — gh extension install github/gh-stack, then make sure the repo is allow-listed at gh.io/stacksbeta (private preview as of 2026-05).

Once one of those is installed, re-invoke /pr-stack and I'll drive it.

Do not improvise with plain git push chains, parent-target wiring, or manual PR linking — the value of this skill is the stack-aware machinery, and faking it produces a worse outcome than telling the user the tool is missing.

Third failure mode — gh stack installed but the repo isn't allow-listed. The CLI installs anywhere, but remote ops (submit, sync, link) fail with exit code 4 when the repo isn't on the private-preview allow-list. If you see exit 4, surface this and point the user at gh.io/stacksbeta. If gt is also installed locally, offer to fall back to it for this repo.

Mental model (shared)

  • Trunk is main (or whatever the repo calls it).
  • Stack is a chain of branches, each parented on the previous one. The bottom of every stack is trunk.
  • One PR per branch, each PR targeting its parent branch. The chain reviews bottom-up.
  • Submit pushes the whole chain and opens / updates one PR per branch.
  • Sync pulls trunk, restacks every surviving branch onto the new trunk tip, and prunes branches whose PRs have merged.

All three tools implement this model. Command names diverge — see the per-tool reference.

After a PR in the stack merges

When the bottom (or any merged) PR lands, the rest of the stack needs to follow trunk forward and the merged branch needs to drop out. This is a distinct moment — don't wait for it to come up in normal "sync" cadence.

Run the tool's sync command:

ToolCommandWhat it does
gtgt sync then gt submit --stackFetches trunk, restacks survivors onto the new trunk tip locally, prompts to delete merged / closed branches. Then submit pushes the rebased survivors.
gh stackgh stack sync (gh stack submit only if you have unpushed local commits)GitHub already cascaded the rebase server-side at merge time; sync mostly pulls that state down and updates local refs.
git towngit town sync --stackFetches trunk, drops the merged branch, rebases the survivors onto the new trunk tip locally, and force-pushes them so the forge re-targets their PRs.

Key divergence: with gh stack the survivors were already rebased by the GitHub server when the bottom PR merged — your job is to pull that state down, not to recompute it. With gt the rebase is local, so gt sync does the actual work on your machine.

If sync hits a conflict (trunk and a survivor touched the same lines), drop into the tool's conflict-recovery flow — gt continue / gt abort, git town continue / git town skip, or gh stack rebase --continue / --abort. Never reach for bare git rebase --continue; the tool's metadata won't advance.

After sync succeeds, run gt log short / git town branch / gh stack view to confirm the chain looks right before the next submit.

Tool-equivalence cheat sheet

Actiongtgit towngh stack
Initialize stack metadatagt init (repo-level)git town config setup (repo-level)gh stack init (per-stack)
Start a stack off trunkgt create on trunkgit town hack <name>gh stack init + gh stack add
Create branch on topgt create -am "msg"git town append <name> (then commit)gh stack add -Am "msg"
Amend tip + restack childrengt modify -aedit, then git town sync --stack(edit, then gh stack push)
New commit + restack childrengt modify -cam "msg"commit, then git town sync --stack(commit, then gh stack push)
Inspect stackgt log short (gt ls)git town branchgh stack view (-s short)
Pull trunk + restackgt syncgit town sync --stackgh stack sync
Cascade restack onlygt restackgit town sync --stack --no-pushgh stack rebase
Submit / update PRsgt submit --stack (gt ss)git town propose --stackgh stack submit
Adopt a plain-git branchgt track (any time)git town set-parent (any time)gh stack init --adopt (init-time only)
Move up / down in stackgt up / gt downgit town switch (picker)gh stack up / gh stack down
Continue after conflictgt continuegit town continuegh stack rebase --continue
Abort / skip halted opgt abortgit town skip / git town undogh stack rebase --abort
Open existing PRs as stackn/an/a (set parents, then propose --stack)gh stack link <PRs...>

When in doubt about flags, always defer to the per-tool reference, not to memory — all three CLIs drift between versions.

Rules (apply to all three tools)

  • Don't reach into git rebase mid-stack. Use the tool's sync / restack / modify commands so children stay parented correctly.
  • Don't git push a single branch in a stack. Use the tool's submit / push command — bare push skips the parent-target wiring and leaves the rest of the stack stale.
  • Stage explicitly. All three tools follow the staged set the way git commit does. Stage by name; avoid git add -A.
  • One concern per branch. That's the whole point of stacking — keep each PR reviewable in isolation.
  • After a rebase conflict, use the tool's continue / abort, never bare git rebase --continue / --abort — the tool's metadata won't update otherwise.

Handoffs

  • Staging and crafting commit messages → /commit
  • PR review, CI checks, merge, comments → /gh
  • Pre-commit hooks complaining → /prek

When to read references

  • references/gt.md — full gt command surface (create / modify / sync / submit / track / log), install + auth, restack recipes, conflict recovery, monorepo / multi-trunk caveats. Read when detection picks gt.
  • references/git-town.md — full git town command surface (hack / append / sync / propose / set-parent / ship), install + forge auth, conflict recovery, config keys, squash-merge gotcha. Read when detection picks git town.
  • references/gh-stack.md — full gh stack command surface, install + waitlist, exit codes, conflict recovery, divergence from gt. Read when detection picks gh stack.

Comments

Markdown supported