@cvr/stacked 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,12 +10,19 @@ Built with [Effect v4](https://effect.website) and [Bun](https://bun.sh).
10
10
  bun run build # compiles binary to bin/stacked + symlinks to ~/.bun/bin/
11
11
  ```
12
12
 
13
- ## Usage
13
+ ## Setup
14
14
 
15
15
  ```sh
16
- # Set trunk branch (default: main)
16
+ # Trunk is auto-detected (main > master > develop). Override if needed:
17
17
  stacked trunk develop
18
18
 
19
+ # Install the Claude skill (optional):
20
+ stacked init
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```sh
19
26
  # Create a stack: branch from trunk
20
27
  stacked create feat-auth
21
28
 
@@ -24,17 +31,26 @@ stacked create feat-auth-ui
24
31
 
25
32
  # See the stack
26
33
  stacked list
34
+ stacked list --json # machine-readable output
27
35
 
28
36
  # See a specific stack by name
29
37
  stacked list feat-auth
30
38
 
39
+ # Quick orientation
40
+ stacked status
41
+ stacked status --json
42
+
31
43
  # List all stacks in the repo
32
44
  stacked stacks
45
+ stacked stacks --json
33
46
 
34
47
  # Navigate
35
- stacked top
36
- stacked bottom
48
+ stacked up # move up one branch
49
+ stacked down # move down one branch
50
+ stacked top # jump to top of stack
51
+ stacked bottom # jump to bottom of stack
37
52
  stacked checkout feat-auth
53
+ stacked checkout any-branch # falls through to git for non-stacked branches
38
54
 
39
55
  # Sync entire stack with latest trunk
40
56
  stacked sync
@@ -42,9 +58,13 @@ stacked sync
42
58
  # After editing mid-stack, rebase only children
43
59
  stacked sync --from feat-auth
44
60
 
45
- # Push all branches + create/update PRs
61
+ # Push all branches + create/update PRs (force-pushes by default)
46
62
  stacked submit
47
63
  stacked submit --draft
64
+ stacked submit --title "Add auth" --body "Implements OAuth2 flow"
65
+ stacked submit --title "Auth,Validation,Tests" # per-branch titles (comma-delimited)
66
+ stacked submit --only # process only the current branch
67
+ stacked submit --no-force # disable force-push
48
68
  stacked submit --dry-run
49
69
 
50
70
  # Adopt an existing branch into the stack
@@ -52,37 +72,73 @@ stacked adopt existing-branch --after feat-auth
52
72
 
53
73
  # View commits per branch
54
74
  stacked log
75
+ stacked log --json
76
+
77
+ # Detect existing branch chains and register as stacks
78
+ stacked detect
79
+ stacked detect --dry-run
55
80
 
56
- # Remove merged branches from stacks
81
+ # Remove merged branches from stacks (prompts for confirmation)
57
82
  stacked clean
58
83
  stacked clean --dry-run
84
+ stacked clean --yes # skip confirmation
59
85
 
60
- # Remove a branch from the stack
86
+ # Remove a branch from the stack (prompts for confirmation)
61
87
  stacked delete feat-auth-ui
88
+ stacked delete feat-auth-ui --keep-remote # keep the remote branch
89
+ stacked delete feat-auth-ui --yes # skip confirmation
90
+
91
+ # Global flags (work with any command)
92
+ stacked --verbose list # debug output
93
+ stacked --quiet sync # suppress non-essential output
94
+ stacked --no-color list # disable colored output
95
+ stacked --yes clean # skip confirmation prompts
62
96
  ```
63
97
 
64
98
  ## Commands
65
99
 
66
- | Command | Description |
67
- | ----------------- | ------------------------------------------------------------- |
68
- | `trunk [name]` | Get/set trunk branch |
69
- | `create <name>` | Create branch on top of current |
70
- | `list [stack]` | Show stack branches (defaults to current stack) |
71
- | `stacks` | List all stacks in the repo |
72
- | `checkout <name>` | Switch to branch |
73
- | `top` | Jump to top of stack |
74
- | `bottom` | Jump to bottom of stack |
75
- | `sync` | Fetch + rebase stack on trunk (--from to start from a branch) |
76
- | `clean` | Remove merged branches from stacks (--dry-run to preview) |
77
- | `delete <name>` | Remove branch from stack + git |
78
- | `submit` | Push all + create/update PRs via `gh` |
79
- | `adopt <branch>` | Add existing branch to stack |
80
- | `log` | Show commits grouped by branch |
100
+ | Command | Description |
101
+ | ----------------- | ------------------------------------------------------------------------------ |
102
+ | `trunk [name]` | Get/set trunk branch (`--json`) |
103
+ | `create <name>` | Create branch on top of current (`--from`, `--json`) |
104
+ | `list [stack]` | Show stack branches (`--json`) |
105
+ | `stacks` | List all stacks (`--json`) |
106
+ | `status` | Show current branch, stack position, working tree state (`--json`) |
107
+ | `checkout <name>` | Switch to branch (falls through to git for non-stacked branches) |
108
+ | `up` | Move up one branch in the stack |
109
+ | `down` | Move down one branch in the stack |
110
+ | `top` | Jump to top of stack |
111
+ | `bottom` | Jump to bottom of stack |
112
+ | `sync` | Fetch + rebase stack on trunk (`--from` to start from a branch) |
113
+ | `detect` | Detect branch chains and register as stacks (`--dry-run`, `--json`) |
114
+ | `clean` | Remove merged branches + remote branches (`--dry-run`, `--json`) |
115
+ | `delete <name>` | Remove branch from stack + git + remote (`--keep-remote`, `--force`, `--json`) |
116
+ | `submit` | Push + create/update PRs (`--title`, `--body`, `--only`, `--draft`, `--json`) |
117
+ | `adopt <branch>` | Add existing branch to stack (`--after`, `--json`) |
118
+ | `log` | Show commits grouped by branch (`--json`) |
119
+ | `init` | Install the stacked Claude skill to ~/.claude/skills |
120
+
121
+ ### Global Flags
122
+
123
+ | Flag | Description |
124
+ | -------------- | ----------------------------- |
125
+ | `--verbose` | Enable debug output |
126
+ | `--quiet`/`-q` | Suppress non-essential output |
127
+ | `--no-color` | Disable colored output |
128
+ | `--yes`/`-y` | Skip confirmation prompts |
81
129
 
82
130
  ## Data Model
83
131
 
84
132
  Stack metadata lives in `.git/stacked.json`. Each branch's parent is implied by array position — `branches[0]`'s parent is trunk, `branches[n]`'s parent is `branches[n-1]`.
85
133
 
134
+ Trunk is auto-detected on first use by checking for `main`, `master`, or `develop` branches. Override with `stacked trunk <name>`.
135
+
136
+ ## Output Conventions
137
+
138
+ - **stdout**: data output only (JSON, branch names, tree views) — safe for piping
139
+ - **stderr**: progress messages, spinners, success/warning/error messages
140
+ - All commands support `--json` for structured output
141
+
86
142
  ## Development
87
143
 
88
144
  ```sh
package/bin/stacked CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cvr/stacked",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cevr/stacked"
@@ -33,7 +33,8 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@effect/platform-bun": "4.0.0-beta.12",
36
- "effect": "4.0.0-beta.12"
36
+ "effect": "4.0.0-beta.12",
37
+ "picocolors": "^1.1.1"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@changesets/changelog-github": "^0.5.2",
package/scripts/build.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { mkdirSync, lstatSync, unlinkSync, symlinkSync } from "fs";
1
+ import { mkdirSync, lstatSync, unlinkSync, symlinkSync, readFileSync } from "fs";
2
2
  import { dirname, join } from "path";
3
3
  import { fileURLToPath } from "url";
4
4
  import * as os from "node:os";
@@ -7,6 +7,9 @@ const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = dirname(__filename);
8
8
  const rootDir = join(__dirname, "..");
9
9
 
10
+ const pkg = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf-8"));
11
+ const skillContent = readFileSync(join(rootDir, "skills", "stacked", "SKILL.md"), "utf-8");
12
+
10
13
  console.log("Building stacked...");
11
14
 
12
15
  const binDir = join(rootDir, "bin");
@@ -20,6 +23,10 @@ const buildResult = await Bun.build({
20
23
  entrypoints: [join(rootDir, "src/main.ts")],
21
24
  target: "bun",
22
25
  minify: false,
26
+ define: {
27
+ __VERSION__: JSON.stringify(pkg.version),
28
+ __SKILL_CONTENT__: JSON.stringify(skillContent),
29
+ },
23
30
  compile: {
24
31
  target: `bun-${platform}-${arch}`,
25
32
  outfile: join(binDir, "stacked"),
@@ -16,40 +16,69 @@ What do you need?
16
16
  ├─ Start a new stack → §Creating a Stack
17
17
  ├─ Add branches to a stack → §Creating a Stack
18
18
  ├─ See current stack → §Viewing the Stack
19
+ ├─ Quick orientation → §Status
19
20
  ├─ Navigate between branches → §Navigation
20
21
  ├─ Rebase after changes → §Rebasing
22
+ ├─ Amend + auto-rebase → §Amending
21
23
  ├─ Push + create PRs → §Submitting
22
24
  ├─ Adopt existing branches → §Adopting Branches
25
+ ├─ Detect existing branches → §Detecting Existing Branches
26
+ ├─ Clean up merged branches → §Cleaning Up Merged Branches
23
27
  ├─ Remove a branch → §Deleting
28
+ ├─ Reorganize stack → §Stack Management
29
+ ├─ Check metadata health → §Doctor
30
+ ├─ Install Claude skill → §Setup
24
31
  └─ Troubleshooting → §Gotchas
25
32
  ```
26
33
 
27
34
  ## Quick Reference
28
35
 
29
- | Command | What it does |
30
- | ------------------------- | ------------------------------------------------------------- |
31
- | `stacked trunk [name]` | Get/set trunk branch (default: main) |
32
- | `stacked create <name>` | Create branch on top of current branch |
33
- | `stacked list [stack]` | Show stack branches (defaults to current stack) |
34
- | `stacked stacks` | List all stacks in the repo |
35
- | `stacked checkout <name>` | Switch to branch in stack |
36
- | `stacked top` | Jump to top of stack |
37
- | `stacked bottom` | Jump to bottom of stack |
38
- | `stacked sync` | Fetch + rebase stack on trunk (--from to start from a branch) |
39
- | `stacked clean` | Remove merged branches from stacks (--dry-run to preview) |
40
- | `stacked delete <name>` | Remove branch from stack + delete git branch |
41
- | `stacked submit` | Push all branches + create/update PRs via `gh` |
42
- | `stacked adopt <branch>` | Add existing git branch into the stack |
43
- | `stacked log` | Show commits grouped by branch |
36
+ | Command | What it does |
37
+ | ---------------------------- | ------------------------------------------------------------------------------------------- |
38
+ | `stacked trunk [name]` | Get/set trunk branch (`--json`) |
39
+ | `stacked create <name>` | Create branch on top of current (`--from`, `--json`) |
40
+ | `stacked list [stack]` | Show stack branches (`--json`) |
41
+ | `stacked stacks` | List all stacks in the repo (`--json`) |
42
+ | `stacked status` | Show current branch, stack position, working tree state (`--json`) |
43
+ | `stacked checkout <name>` | Switch to branch (falls through to git for non-stacked branches) |
44
+ | `stacked up` | Move up one branch in the stack |
45
+ | `stacked down` | Move down one branch in the stack |
46
+ | `stacked top` | Jump to top of stack |
47
+ | `stacked bottom` | Jump to bottom of stack |
48
+ | `stacked sync` | Fetch + rebase stack on trunk (`--from`, `--dry-run`, `--json`) |
49
+ | `stacked detect` | Detect branch chains and register as stacks (`--dry-run`, `--json`) |
50
+ | `stacked clean` | Remove merged branches + remote branches (`--dry-run`, `--json`) |
51
+ | `stacked delete <name>` | Remove branch from stack + git + remote (`--keep-remote`, `--force`, `--dry-run`, `--json`) |
52
+ | `stacked submit` | Push + create/update PRs (`--title`, `--body`, `--only`, `--draft`, `--json`) |
53
+ | `stacked adopt <branch>` | Add existing git branch into the stack (`--after`, `--json`) |
54
+ | `stacked log` | Show commits grouped by branch (`--json`) |
55
+ | `stacked amend` | Amend current commit and rebase children (`--edit`, `--from`, `--json`) |
56
+ | `stacked doctor` | Check stack metadata for issues (`--fix`, `--json`) |
57
+ | `stacked rename <old> <new>` | Rename a stack (`--json`) |
58
+ | `stacked reorder <branch>` | Move a branch within the stack (`--before`, `--after`, `--json`) |
59
+ | `stacked split <branch>` | Split stack at a branch point (`--dry-run`, `--json`) |
60
+ | `stacked init` | Install the stacked Claude skill to ~/.claude/skills |
61
+
62
+ ### Global Flags
63
+
64
+ | Flag | Description |
65
+ | -------------- | ----------------------------- |
66
+ | `--verbose` | Enable debug output |
67
+ | `--quiet`/`-q` | Suppress non-essential output |
68
+ | `--no-color` | Disable colored output |
69
+ | `--yes`/`-y` | Skip confirmation prompts |
44
70
 
45
71
  ## Setup
46
72
 
47
73
  ```sh
48
- # Set trunk if not "main"
74
+ # Trunk is auto-detected (main > master > develop). Override if needed:
49
75
  stacked trunk develop
76
+
77
+ # Install the Claude skill (optional, compiled binary only):
78
+ stacked init
50
79
  ```
51
80
 
52
- Requires `gh` CLI installed and authenticated for `submit`.
81
+ Requires `gh` CLI installed and authenticated for `submit` and `clean`.
53
82
 
54
83
  ## Creating a Stack
55
84
 
@@ -75,26 +104,50 @@ stacked create hotfix --from feat-auth
75
104
  ## Viewing the Stack
76
105
 
77
106
  ```sh
78
- stacked list # shows current stack's branches
107
+ stacked list # shows current stack's branches (colored tree view)
79
108
  stacked list feat-auth # shows a specific stack by name
109
+ stacked list --json # machine-readable JSON output
80
110
  stacked stacks # lists all stacks in the repo
111
+ stacked stacks --json # machine-readable JSON output
81
112
  stacked log # shows commits grouped by branch
113
+ stacked log --json # machine-readable JSON output
114
+ ```
115
+
116
+ ## Status
117
+
118
+ Quick orientation — shows current branch, working tree state, and stack position:
119
+
120
+ ```sh
121
+ stacked status
122
+ # Branch: feat-auth-ui
123
+ # Working tree: clean
124
+ # Stack: feat-auth (2 of 3)
125
+
126
+ stacked status --json
127
+ # { "branch": "feat-auth-ui", "clean": true, "stack": { "name": "feat-auth", "position": 2, "total": 3 } }
82
128
  ```
83
129
 
84
130
  ## Navigation
85
131
 
86
132
  ```sh
87
- stacked checkout feat-auth # switch to specific branch
88
- stacked top # jump to top of stack
89
- stacked bottom # jump to bottom (trunk-adjacent)
133
+ stacked up # move up one branch
134
+ stacked down # move down one branch
135
+ stacked checkout feat-auth # switch to specific branch
136
+ stacked checkout any-branch # falls through to git for non-stacked branches
137
+ stacked top # jump to top of stack
138
+ stacked bottom # jump to bottom (trunk-adjacent)
90
139
  ```
91
140
 
141
+ All navigation commands support `--json` for structured output. `checkout` falls through to `git checkout` for branches not in any stack.
142
+
92
143
  ## Syncing / Rebasing
93
144
 
94
145
  Fetch latest trunk and rebase the entire stack bottom-to-top:
95
146
 
96
147
  ```sh
97
148
  stacked sync
149
+ stacked sync --dry-run # preview rebase plan without executing
150
+ stacked sync --json # structured output: { branches: [{ name, action, base }] }
98
151
  ```
99
152
 
100
153
  After mid-stack changes, rebase only the branches above a specific point:
@@ -105,18 +158,45 @@ stacked checkout feat-auth
105
158
  stacked sync --from feat-auth # rebases only children of feat-auth
106
159
  ```
107
160
 
161
+ **Note:** `sync` requires a clean working tree — commit or stash before running (except with `--dry-run`). On rebase conflict, the rebase is left in progress so you can resolve it:
162
+
163
+ ```sh
164
+ # On conflict:
165
+ git rebase --continue # after resolving conflicts
166
+ stacked sync --from <parent-branch> # resume syncing remaining branches
167
+ ```
168
+
169
+ ## Amending
170
+
171
+ Amend the current commit and auto-rebase child branches:
172
+
173
+ ```sh
174
+ stacked amend # amend + rebase children
175
+ stacked amend --edit # open editor for commit message
176
+ stacked amend --from feat-auth # start rebasing from a specific branch
177
+ stacked amend --json # structured output
178
+ ```
179
+
108
180
  ## Submitting
109
181
 
110
182
  Push all stack branches and create/update GitHub PRs with correct base branches:
111
183
 
112
184
  ```sh
113
- stacked submit # push + create/update PRs
114
- stacked submit --draft # create as draft PRs
115
- stacked submit --force # force push
116
- stacked submit --dry-run # show what would happen
185
+ stacked submit # push + create/update PRs
186
+ stacked submit --draft # create as draft PRs
187
+ stacked submit --title "Add auth" --body "OAuth2" # with title and body
188
+ stacked submit --title "Auth,Validation,Tests" # per-branch titles (comma-delimited)
189
+ stacked submit --only # process only the current branch
190
+ stacked submit --no-force # disable force-push
191
+ stacked submit --dry-run # show what would happen
192
+ stacked submit --json # structured JSON output
117
193
  ```
118
194
 
119
- Each PR targets its parent branch (not trunk), preserving the stack structure on GitHub.
195
+ Force-push (with lease) is the default because stacked branches are always rebased. Use `--no-force` if you haven't rebased.
196
+
197
+ Each PR targets its parent branch (not trunk), preserving the stack structure on GitHub. PRs include auto-generated stack metadata showing position and navigation links. The metadata is refreshed on every `submit`.
198
+
199
+ **Output:** `submit` prints one line per branch to stdout: `<branch> #<number> <url> <action>`. With `--json`, outputs a structured `{ results: [...] }` array.
120
200
 
121
201
  ## Adopting Branches
122
202
 
@@ -127,24 +207,107 @@ stacked adopt existing-branch # append to top
127
207
  stacked adopt existing-branch --after feat-auth # insert after specific branch
128
208
  ```
129
209
 
210
+ ## Detecting Existing Branches
211
+
212
+ Auto-detect linear branch chains from git history and register them as stacks:
213
+
214
+ ```sh
215
+ stacked detect # scan and register branch chains
216
+ stacked detect --dry-run # preview what would be registered
217
+ stacked detect --json # structured JSON output
218
+ ```
219
+
220
+ Only linear chains are detected. Forked branches (one parent with multiple children) are reported but skipped. Already-tracked branches are excluded.
221
+
130
222
  ## Cleaning Up Merged Branches
131
223
 
132
- After PRs are merged on GitHub, clean up the local branches and stack metadata:
224
+ After PRs are merged on GitHub, clean up the local and remote branches and stack metadata:
133
225
 
134
226
  ```sh
135
- stacked clean # removes all merged branches from all stacks
227
+ stacked clean # removes all merged branches (prompts for confirmation)
136
228
  stacked clean --dry-run # preview what would be removed
229
+ stacked clean --json # structured JSON output
230
+ stacked clean --yes # skip confirmation prompt
137
231
  ```
138
232
 
139
- `list` also shows merge status per branch (`[merged]`, `[closed]`, `[#N]` for open PRs).
233
+ `clean` also deletes the corresponding remote branches. `list` shows merge status per branch (`[merged]`, `[closed]`, `[#N]` for open PRs). After cleaning, run `stacked sync` to rebase remaining branches.
140
234
 
141
235
  ## Deleting
142
236
 
143
237
  ```sh
144
- stacked delete feat-auth-ui # removes from stack + deletes git branch
145
- stacked delete feat-auth-ui --force # skip confirmation
238
+ stacked delete feat-auth-ui # removes from stack + deletes local + remote branch
239
+ stacked delete feat-auth-ui --force # skip children check
240
+ stacked delete feat-auth-ui --keep-remote # don't delete remote branch
241
+ stacked delete feat-auth-ui --dry-run # show what would happen
242
+ stacked delete feat-auth-ui --json # structured JSON output
146
243
  ```
147
244
 
245
+ Deleting a mid-stack branch with `--force` warns about potentially lost commits and recommends running `stacked sync` to rebase child branches onto the new parent.
246
+
247
+ ## Stack Management
248
+
249
+ Rename, reorder, and split stacks:
250
+
251
+ ```sh
252
+ # Rename a stack (metadata only, doesn't rename branches)
253
+ stacked rename old-name new-name
254
+
255
+ # Move a branch to a different position in the stack
256
+ stacked reorder feat-b --before feat-a
257
+ stacked reorder feat-b --after feat-c
258
+
259
+ # Split a stack at a branch point (branches at/above become a new stack)
260
+ stacked split feat-b
261
+ stacked split feat-b --dry-run # preview the split
262
+ ```
263
+
264
+ After reordering, run `stacked sync` to rebase branches in new order.
265
+
266
+ ## Doctor
267
+
268
+ Check stack metadata for issues (stale branches, missing trunk, duplicates):
269
+
270
+ ```sh
271
+ stacked doctor # report issues
272
+ stacked doctor --fix # auto-fix where possible (remove stale branches, auto-detect trunk)
273
+ stacked doctor --json # structured output
274
+ ```
275
+
276
+ ## Error Codes
277
+
278
+ All errors include a machine-readable code for programmatic handling:
279
+
280
+ | Code | Meaning |
281
+ | --------------------- | ------------------------------------------- |
282
+ | `BRANCH_EXISTS` | Branch already exists |
283
+ | `BRANCH_NOT_FOUND` | Branch not found in any stack |
284
+ | `NOT_IN_STACK` | Current branch not tracked in a stack |
285
+ | `DIRTY_WORKTREE` | Working tree has uncommitted changes |
286
+ | `REBASE_CONFLICT` | Rebase conflict during sync/amend |
287
+ | `GH_NOT_INSTALLED` | `gh` CLI not installed or not authenticated |
288
+ | `STACK_NOT_FOUND` | Stack not found |
289
+ | `STACK_EXISTS` | Stack name already taken |
290
+ | `INVALID_BRANCH_NAME` | Branch name fails validation |
291
+ | `ALREADY_AT_TOP` | Already at top of stack |
292
+ | `ALREADY_AT_BOTTOM` | Already at bottom of stack |
293
+ | `TRUNK_ERROR` | Trunk-related error |
294
+
295
+ Usage errors (invalid args, bad state) exit code 2. Operational errors (git/gh failures) exit code 1.
296
+
297
+ ## Idempotent Commands
298
+
299
+ `create` and `adopt` are idempotent:
300
+
301
+ - `create` succeeds silently if the branch already exists and is tracked
302
+ - `adopt` succeeds silently if the branch is already in the current stack (errors only if in a different stack)
303
+
304
+ ## Output Conventions
305
+
306
+ - **stdout**: data output only (JSON, branch names, tree views) — safe for piping
307
+ - **stderr**: progress messages, spinners, success/warning/error messages
308
+ - All write commands support `--json` for structured output
309
+ - Colored output respects `NO_COLOR`, `FORCE_COLOR`, and `--no-color`
310
+
148
311
  ## Data Model
149
312
 
150
313
  Stack metadata lives in `.git/stacked.json`. Each branch's parent is implied by array position:
@@ -152,6 +315,8 @@ Stack metadata lives in `.git/stacked.json`. Each branch's parent is implied by
152
315
  - `branches[0]` → parent is trunk
153
316
  - `branches[n]` → parent is `branches[n-1]`
154
317
 
318
+ Trunk is auto-detected on first use by checking for `main`, `master`, or `develop` branches. Override with `stacked trunk <name>`.
319
+
155
320
  A repo can have multiple independent stacks. The current stack is determined by which branch you're on.
156
321
 
157
322
  ## Typical Workflow
@@ -165,25 +330,42 @@ stacked create feat-auth
165
330
  stacked create feat-auth-ui
166
331
  # ... work, commit ...
167
332
 
168
- # 3. Need to fix something mid-stack
333
+ # 3. Quick check
334
+ stacked status
335
+
336
+ # 4. Need to fix something mid-stack
169
337
  stacked checkout feat-auth
170
338
  # ... fix, commit ...
171
339
  stacked sync --from feat-auth # rebase children
172
340
 
173
- # 4. Sync with latest main
341
+ # 5. Sync with latest main
174
342
  stacked sync
175
343
 
176
- # 5. Submit for review
177
- stacked submit --draft
344
+ # 6. Submit for review
345
+ stacked submit --draft --title "Add auth" --body "Implements OAuth2 flow"
178
346
 
179
- # 6. After review, final submit
347
+ # 7. After review, final submit
180
348
  stacked submit
349
+
350
+ # 8. Navigate quickly
351
+ stacked up # go to next branch
352
+ stacked down # go to previous branch
181
353
  ```
182
354
 
183
355
  ## Gotchas
184
356
 
357
+ - `stacked sync` requires a clean working tree — commit or stash first (except `--dry-run`)
185
358
  - `stacked sync` rebases bottom-to-top — resolve conflicts one branch at a time
186
- - `stacked submit` requires `gh` CLI authenticated (`gh auth login`)
359
+ - `stacked sync` leaves rebase in progress on conflict — resolve with `git rebase --continue`, then resume with `stacked sync --from <parent>`
360
+ - `stacked submit` force-pushes by default (use `--no-force` to disable)
361
+ - `stacked submit` and `stacked clean` require `gh` CLI authenticated (`gh auth login`)
187
362
  - PRs target parent branches, not trunk — this is intentional for stacked review
188
- - Trunk defaults to `main` use `stacked trunk <name>` if your default branch differs
189
- - Rebase conflicts mid-stack will pause the operationresolve and re-run
363
+ - PRs include auto-generated stack metadata (position, navigation links)
364
+ - Trunk is auto-detected (`main` > `master` > `develop`) use `stacked trunk <name>` to override
365
+ - Forked branches (one parent, multiple children) are not supported — `detect` reports them but skips
366
+ - `stacked delete --force` on a mid-stack branch requires `stacked sync` afterward
367
+ - `stacked checkout` falls through to `git checkout` for branches not in a stack
368
+ - Detached HEAD is detected and produces a clear error — checkout a branch first
369
+ - Stack file writes are atomic (write to tmp, then rename) to prevent corruption
370
+ - `create` and `adopt` are idempotent — safe to re-run after transient failures
371
+ - Use `stacked doctor` to detect and fix metadata drift (stale branches, missing trunk)