|
| 1 | +# Rebase Stack Workflow |
| 2 | + |
| 3 | +Rebases a stacked-branch chain onto an updated base branch using `gh stack`, |
| 4 | +guides you through conflict resolution if needed, validates each branch, and |
| 5 | +pushes all updated branches. Creates any missing PRs afterwards, with |
| 6 | +fork-aware targeting. |
| 7 | + |
| 8 | +## Phase Flow |
| 9 | + |
| 10 | +``` |
| 11 | +/start ──── success ──────────────────────── /validate ──── /push ──── done |
| 12 | + └─── conflict ──── (resolve) ──── /continue ──┐ |
| 13 | + │ |
| 14 | + conflict ──── (resolve) ────┘ |
| 15 | + success ──────────────── /validate ──── /push ──── done |
| 16 | +``` |
| 17 | + |
| 18 | +## Prerequisites |
| 19 | + |
| 20 | +| Tool | Purpose | |
| 21 | +|------|---------| |
| 22 | +| `git` | Rebase and push operations | |
| 23 | +| `gh` (GitHub CLI) | Stack management, PR creation | |
| 24 | +| `gh-stack` extension | `gh extension install github/gh-stack` | |
| 25 | +| Remote access (`origin`) | Fetch and push | |
| 26 | + |
| 27 | +`/start` installs the extension automatically if it is not found. |
| 28 | + |
| 29 | +> **Note:** `gh-stack` is in private preview. The CLI extension installs for |
| 30 | +> anyone, but the Stacked PRs feature (used by `gh stack submit`) requires |
| 31 | +> enablement on the upstream repository. If `gh stack submit` exits with |
| 32 | +> code 9, the repo does not have it enabled — the skill falls back to |
| 33 | +> `gh pr create` automatically. |
| 34 | +
|
| 35 | +## Stack Initialization |
| 36 | + |
| 37 | +`/start` detects whether your branches are already tracked by `gh stack`: |
| 38 | + |
| 39 | +- **Already tracked** (`gh stack view --json` exits 0): proceeds directly to |
| 40 | + the rebase. |
| 41 | +- **Not yet tracked** (exit code 2): discovers branches from the commit graph |
| 42 | + (`git log --reverse --decorate origin/{base}..HEAD`), presents the |
| 43 | + bottom-to-top list for your confirmation, then runs: |
| 44 | + ```bash |
| 45 | + gh stack init --base {base} branch-1 branch-2 branch-3 ... |
| 46 | + ``` |
| 47 | + `gh stack` adopts the existing branches and detects any open PRs automatically. |
| 48 | + |
| 49 | +You only need to initialize once per stack. Subsequent `/start` runs skip |
| 50 | +this step. |
| 51 | + |
| 52 | +## Commands |
| 53 | + |
| 54 | +| Command | When to use | |
| 55 | +|---------|-------------| |
| 56 | +| `/start` | Begin the rebase. Takes an optional base branch (default: `main`). Installs `gh-stack` if needed, initializes the stack if not yet tracked, then rebases. Local only — does not push. | |
| 57 | +| `/continue` | Resume after resolving a conflict mid-rebase. Repeat as needed. Local only — does not push. | |
| 58 | +| `/validate` | After rebase completes: re-fetches to check remote currency, runs lint and unit tests on each branch independently, and shows a branch overview table. Does not push. | |
| 59 | +| `/push` | After validation: asks for confirmation, pushes all branches atomically with `gh stack push`, then creates any missing PRs with fork-aware targeting. | |
| 60 | + |
| 61 | +## Usage Examples |
| 62 | + |
| 63 | +### Typical: rebase a stack onto updated main |
| 64 | + |
| 65 | +You have three branches stacked: `main → story-1 → story-2 → story-3 (HEAD)`. |
| 66 | +Main has moved forward. Run: |
| 67 | + |
| 68 | +``` |
| 69 | +/start |
| 70 | +``` |
| 71 | + |
| 72 | +The agent checks for `gh-stack`, detects the stack (or initializes it), |
| 73 | +then runs `gh stack rebase --remote origin`. On success it prompts you to |
| 74 | +run `/validate`, which checks each branch and shows an overview table. Then |
| 75 | +run `/push` to push all branches atomically with `gh stack push` after |
| 76 | +confirmation. |
| 77 | + |
| 78 | +### With conflicts |
| 79 | + |
| 80 | +Same scenario, but `story-2` conflicts with a change on main: |
| 81 | + |
| 82 | +1. `/start` — rebase stops at `story-2`, shows the conflicting files |
| 83 | +2. Resolve conflicts. For "old version vs evolved version" conflicts (the lower |
| 84 | + branch was rebased and this branch has older copies): `git checkout --ours <file> && git add <file>`. |
| 85 | + For genuine new-code conflicts: merge manually, then `git add <file>`. Do not `git commit`. |
| 86 | +3. `/continue` — rebase resumes; if clean, prompts you to run `/validate` |
| 87 | +4. If another conflict appears, repeat steps 2–3 |
| 88 | +5. `/validate` — shows branch overview table after per-branch lint/test |
| 89 | +6. `/push` — pushes after confirmation, creates any missing PRs |
| 90 | + |
| 91 | +### Rebasing onto a branch other than main |
| 92 | + |
| 93 | +``` |
| 94 | +/start feature/platform-upgrade |
| 95 | +``` |
| 96 | + |
| 97 | +The agent fetches `origin/feature/platform-upgrade` and rebases onto it. |
| 98 | + |
| 99 | +### Fork-based workflow (no Stacked PRs) |
| 100 | + |
| 101 | +After `/push` completes the push, it tries `gh stack submit --auto`. If the |
| 102 | +upstream repo does not have Stacked PRs enabled (exit code 9), it falls back |
| 103 | +to `gh pr create` with `--head fork-owner:branch --repo upstream/repo`, setting |
| 104 | +`Depends on: #N` in each PR body. All PRs target the upstream default branch. |
| 105 | + |
| 106 | +## Artifacts |
| 107 | + |
| 108 | +Local state written to `.artifacts/rebase-stack/` during the workflow (gitignored): |
| 109 | + |
| 110 | +| File | Written by | Purpose | How to clear | |
| 111 | +|------|-----------|---------|--------------| |
| 112 | +| `validation-cache` | `/validate` | `branch:sha` pairs for each branch that has passed validation. Persists across runs; stale entries are ignored automatically when SHAs change after a rebase. | `rm .artifacts/rebase-stack/validation-cache` to force full re-validation on the next `/validate` run. | |
| 113 | +| `logs/{branch}.log` | `/validate` | Full lint and test output per branch. Kept on failure for inspection; deleted on success. | Inspect directly; deleted automatically on the next successful `/validate` run. | |
| 114 | + |
| 115 | +## Push Safety |
| 116 | + |
| 117 | +- Branches are pushed **atomically**: `gh stack push` uses `--force-with-lease |
| 118 | + --atomic`, so if any remote branch was updated since the last fetch, the |
| 119 | + entire push is rejected rather than partially applied. |
| 120 | +- Protected branches (`main`, `master`, `develop`, PR targets) are never |
| 121 | + pushed — only the stack branches above them. |
0 commit comments