skills/restack/SKILL.md
Manage stacked branches — rebase cascades, detect landed PRs, show stack status. Use when branches are stacked (B on A on main), trunk has advanced, a mid-stack branch changed, or a PR has landed and descendants need rebasing. Lightweight alternative to Graphite that infers the stack from git history.
npx skillsauth add shhac/skills restackInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Manage stacked branches without external tooling. Infers the dependency graph from git history (merge-base ancestry + commit distance) — no metadata files, no init step, no account.
Handles the common stacking pain points:
/restack [status | sync | <description of what to do>]
This skill includes scripts/restack.py — a deterministic Python helper for graph inference and status detection. Requires Python 3.9+ (stdlib only).
Locate the script relative to this skill file. Invoke as:
python3 <skill-dir>/scripts/restack.py <subcommand> [options]
Subcommands: status, graph, restack, sync, cleanup. Run with --help for full usage. Default output is compact key-value (LLM-friendly). Add --json for structured output.
The script supports three modes for selecting which branches to analyze:
--branches a,b,c — explicit list--prefix paul/ — all branches matching a prefixIf the user has a naming convention (e.g., paul/* branches), use --prefix. Otherwise, let it auto-discover.
You are managing stacked branches. Follow the steps below. This skill uses incremental discovery — read reference files only when triggered by specific conditions.
Reference files live in references/ adjacent to this skill.
Check for interrupted operation. Look for branches matching restack/pre-rebase/*. If found, a previous restack was interrupted. Show the user what backups exist and offer to restore or clean up (python3 <script> cleanup).
Identify trunk. The script auto-detects main or master. If neither exists, ask the user.
Identify branches. If the user specified branches, use those. Otherwise, detect from context:
--prefixGuard working tree. If there are uncommitted changes:
git stash push -m "restack: uncommitted changes"
Run the status command:
python3 <script> status [--trunk <trunk>] [--prefix <prefix> | --branches <list>]
This outputs a tree showing each stack with per-branch state:
ok — branch is based on the current tip of its parentneeds-restack — parent has moved, branch needs rebasinglanded — all patches are in trunk (PR was merged)orphaned — no detectable parentIncremental discovery triggers from status output:
ambiguous entries appear → read references/ambiguous-graph.mdlanded branches appear → read references/landed-branch.mdorphaned branches appear → ask the user what to do (rebase onto trunk, skip, or specify parent)If the user ran /restack with no arguments, present this status and ask what they'd like to do.
Based on user intent and status, pick the appropriate flow:
→ Read references/trunk-advance.md for the basic cascade pattern.
Then read the matching topology reference based on the graph structure:
| Topology detected | Read this file |
|---|---|
| Linear stack (A→B, no branching) | trunk-advance.md is sufficient |
| Three or more branches in a chain (A→B→C→D) | references/deep-chain.md |
| Multiple branches off the same parent (B,C on A) | references/fan-out.md |
| Fan-out with depth (A→B,C and C→D→E) | references/deep-fan.md |
| Fan-out, reconverge, fan-out again (hourglass) | references/fan-deep-fan.md |
| Multiple independent stacks side by side | references/independent-stacks.md |
| Mixed (combination of above) | Read ALL applicable files |
Run the restack command to see the plan:
python3 <script> restack [--trunk <trunk>] [--branches <list>]
This creates backup refs and outputs the rebase plan.
Present the plan to the user. Wait for confirmation.
Execute the rebases in topological order (the order from the output):
git rebase --empty=drop <trunk> <branch>onto-backup): git rebase --empty=drop --onto <parent> restack/pre-rebase/<parent> <branch>restack/pre-rebase/<parent> captures the parent's pre-rebase tip — this is the correct --onto cut point.If a rebase conflicts, resolve the conflict, then git rebase --continue. Continue with the next branch in the cascade.
After each successful rebase, push with --force-with-lease.
After all rebases complete, clean up: python3 <script> cleanup
→ Read references/mid-stack-edit.md for the cascade pattern.
The --branch flag restacks only the descendants of the edited branch (not the branch itself, since the user already changed it).
Run:
python3 <script> restack --branch <edited-branch> [--trunk <trunk>]
The plan output shows the rebase strategy for each branch:
onto-merge-base): Use the merge-base as the cut point, NOT the backup ref. This is because the backup captures the post-edit state:
git rebase --empty=drop --onto <parent> <merge-base> <child>
Any of the parent's old commits that get replayed are dropped by --empty=drop.onto-backup): Use the normal backup ref approach.Execute in topological order, resolve conflicts, push, clean up.
→ Read references/landed-branch.md for landed branch handling.
Fetch the remote and update local trunk:
git fetch origin
git checkout <trunk> && git merge --ff-only origin/<trunk>
Run the sync command to analyze:
python3 <script> sync [--trunk <trunk>] [--branches <list>]
If landed branches are detected, confirm with the user before deleting them:
git branch -D <branch>git push origin --delete <branch>references/mid-stack-landing.mdAfter landed branches are cleaned up, re-run status. If remaining branches need restacking, proceed with the restack flow above.
Two --onto strategies depending on context:
Strategy: onto-backup (normal restack — parent was rebased by this operation):
git rebase --empty=drop --onto <parent> restack/pre-rebase/<parent> <child>
The backup ref is the parent's pre-rebase tip. Takes only the child's unique commits.
Strategy: onto-merge-base (mid-stack edit — parent was changed outside this operation):
mb=$(git merge-base <parent> <child>)
git rebase --empty=drop --onto <parent> $mb <child>
Uses the merge-base because the backup ref would capture the post-edit state. Any parent commits that get replayed are dropped as empty.
Without --onto, a plain git rebase <parent> would replay ALL commits from the merge-base, including the parent's old commits that now have new SHAs — causing duplicates and conflicts.
--force-with-lease when pushing rebased branches, never --force.restack/pre-rebase/* refs.python3 <script> cleanup to remove backup refs.git rebase --continue), then continue the cascade. Only involve the user if the conflict is genuinely ambiguous.development
Review a GitHub pull request using the passive, neutral, assertive, or aggressive profile, optionally paired with a named reviewer persona that sets the review voice, by statically reading the PR diff, metadata, comments, and discovered issue/context links to determine whether it solves the stated issue. Use for automated or manual PR review flows that should leave an emoji-marked top-level review plus targeted inline comments or suggestion blocks, without running code or blocking except for malicious-looking changes.
development
Audit a codebase's module boundaries — enumerate modules, map their seams (import edges between modules), produce a layered topology diagram, and classify each module as narrow, hub-by-design, or accidental hub (with separate flags for cycles, layer violations, and uncertain import graphs). Outputs a diagram plus a flagged-for-review list; does not change code. Use when assessing whether abstractions live at the right boundaries, before/after a refactor to verify the boundaries improved, or when an unfamiliar codebase needs an architectural map. Not for intra-module refactoring (see improve-code-structure), bug hunting, or feature work.
testing
Investigate and solve problems using a team of specialist agents. Use when facing complex, multi-faceted problems that benefit from parallel research and structured implementation.
tools
Sync a forked repository with its upstream. Fetches both remotes, shows divergence, resets shared branches to upstream, re-merges local-only branches, cleans up branches already merged upstream, and pushes. Use when upstream has accepted PRs or moved ahead and you need to bring your fork in line.