dubstack 0.4.0 → 0.5.1
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 +262 -182
- package/dist/index.js +1654 -308
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,320 +1,400 @@
|
|
|
1
1
|
# DubStack
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
DubStack (`dub`) is a local-first CLI for stacked branch workflows.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It is designed for the Graphite mental model: small, dependent PRs that are easy to review, update, and rebase.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Why DubStack
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Large PRs are hard to review and painful to keep up to date.
|
|
10
|
+
|
|
11
|
+
Stacked branches let you split work into focused layers:
|
|
12
|
+
|
|
13
|
+
```text
|
|
10
14
|
(main)
|
|
11
|
-
└─ feat/
|
|
12
|
-
└─ feat/
|
|
13
|
-
└─ feat/
|
|
15
|
+
└─ feat/auth-types
|
|
16
|
+
└─ feat/auth-login
|
|
17
|
+
└─ feat/auth-tests
|
|
14
18
|
```
|
|
15
19
|
|
|
16
|
-
When
|
|
20
|
+
When a lower branch changes, `dub restack` propagates it upstack.
|
|
17
21
|
|
|
18
22
|
## Install
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
### Homebrew (recommended)
|
|
21
25
|
|
|
22
26
|
```bash
|
|
23
27
|
brew tap wiseiodev/dubstack
|
|
24
28
|
brew install dubstack
|
|
25
29
|
```
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
Update:
|
|
28
32
|
|
|
29
33
|
```bash
|
|
30
34
|
brew upgrade dubstack
|
|
31
35
|
```
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
### npm
|
|
34
38
|
|
|
35
39
|
```bash
|
|
36
40
|
npm install -g dubstack
|
|
37
41
|
```
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
> Requires **Node ≥ 22** and **pnpm**.
|
|
43
|
+
### From source
|
|
42
44
|
|
|
43
45
|
```bash
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
git clone https://github.com/wiseiodev/dubstack.git
|
|
47
|
+
cd dubstack
|
|
46
48
|
pnpm install
|
|
47
|
-
|
|
48
|
-
# Link globally so `dub` is available everywhere
|
|
49
49
|
pnpm build
|
|
50
50
|
pnpm link --global
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
## Graphite Mental Model
|
|
54
|
+
|
|
55
|
+
If you have `gt` muscle memory, use this as a fast map:
|
|
56
|
+
|
|
57
|
+
| Graphite (`gt`) | DubStack (`dub`) |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `gt create` | `dub create` |
|
|
60
|
+
| `gt modify` | `dub modify` or `dub m` |
|
|
61
|
+
| `gt submit` / `gt ss` | `dub submit` / `dub ss` |
|
|
62
|
+
| `gt sync` | `dub sync` |
|
|
63
|
+
| `gt checkout` / `gt co` | `dub checkout` / `dub co` |
|
|
64
|
+
| `gt log` / `gt ls` | `dub log` / `dub ls` |
|
|
65
|
+
| `gt up` / `gt down` | `dub up` / `dub down` |
|
|
66
|
+
| `gt top` / `gt bottom` | `dub top` / `dub bottom` |
|
|
67
|
+
| `gt info` | `dub info` |
|
|
68
|
+
| `gt pr` | `dub pr` |
|
|
69
|
+
| `gt restack` | `dub restack` |
|
|
70
|
+
| `gt undo` | `dub undo` |
|
|
71
|
+
|
|
53
72
|
## Quick Start
|
|
54
73
|
|
|
55
74
|
```bash
|
|
56
|
-
# 1
|
|
57
|
-
cd my-project
|
|
58
|
-
dub init
|
|
59
|
-
|
|
60
|
-
# 2. Start stacking branches
|
|
75
|
+
# 1) Start from trunk
|
|
61
76
|
git checkout main
|
|
62
|
-
|
|
63
|
-
# hack hack hack, commit...
|
|
64
|
-
|
|
65
|
-
dub create feat/api-endpoint
|
|
66
|
-
# hack hack hack, commit...
|
|
77
|
+
git pull
|
|
67
78
|
|
|
68
|
-
|
|
69
|
-
#
|
|
79
|
+
# 2) Create stacked branches
|
|
80
|
+
# Create + stage all + commit
|
|
81
|
+
dub create feat/auth-types -am "feat: add auth types"
|
|
82
|
+
dub create feat/auth-login -am "feat: add login flow"
|
|
83
|
+
dub create feat/auth-tests -am "test: add auth tests"
|
|
70
84
|
|
|
71
|
-
# 3
|
|
85
|
+
# 3) View stack
|
|
72
86
|
dub log
|
|
73
87
|
|
|
74
|
-
# 4
|
|
75
|
-
|
|
76
|
-
dub restack
|
|
88
|
+
# 4) Submit stack PRs
|
|
89
|
+
dub ss
|
|
77
90
|
|
|
78
|
-
# 5
|
|
79
|
-
|
|
80
|
-
dub undo
|
|
91
|
+
# 5) Open PR for current branch
|
|
92
|
+
dub pr
|
|
81
93
|
```
|
|
82
94
|
|
|
83
|
-
|
|
95
|
+
For a more detailed walkthrough, see [`QUICKSTART.md`](./QUICKSTART.md).
|
|
96
|
+
|
|
97
|
+
## Command Reference
|
|
84
98
|
|
|
85
|
-
|
|
99
|
+
### `dub init`
|
|
86
100
|
|
|
87
|
-
|
|
101
|
+
Initialize DubStack state in the current git repository.
|
|
88
102
|
|
|
89
103
|
```bash
|
|
90
|
-
|
|
91
|
-
dub skills add
|
|
92
|
-
|
|
93
|
-
# Install specific skill
|
|
94
|
-
dub skills add dub-flow
|
|
104
|
+
dub init
|
|
95
105
|
```
|
|
96
106
|
|
|
97
|
-
|
|
107
|
+
Notes:
|
|
108
|
+
- `dub create` auto-initializes state if needed.
|
|
109
|
+
- Running `dub init` manually is still useful for explicit setup.
|
|
110
|
+
|
|
111
|
+
### `dub create <branch>`
|
|
112
|
+
|
|
113
|
+
Create a branch stacked on top of the current branch.
|
|
98
114
|
|
|
99
115
|
```bash
|
|
100
|
-
#
|
|
101
|
-
|
|
116
|
+
# branch only
|
|
117
|
+
dub create feat/my-change
|
|
118
|
+
|
|
119
|
+
# create + commit staged changes
|
|
120
|
+
dub create feat/my-change -m "feat: ..."
|
|
121
|
+
|
|
122
|
+
# stage all + create + commit
|
|
123
|
+
dub create feat/my-change -am "feat: ..."
|
|
102
124
|
|
|
103
|
-
#
|
|
104
|
-
|
|
125
|
+
# stage tracked-file updates + create + commit
|
|
126
|
+
dub create feat/my-change -um "feat: ..."
|
|
127
|
+
|
|
128
|
+
# interactive hunk staging + create + commit
|
|
129
|
+
dub create feat/my-change -pm "feat: ..."
|
|
105
130
|
```
|
|
106
131
|
|
|
107
|
-
|
|
132
|
+
Flags:
|
|
133
|
+
- `-m, --message <message>`: commit message
|
|
134
|
+
- `-a, --all`: stage all changes before commit (requires `-m`)
|
|
135
|
+
- `-u, --update`: stage tracked-file updates before commit (requires `-m`)
|
|
136
|
+
- `-p, --patch`: select hunks interactively before commit (requires `-m`)
|
|
108
137
|
|
|
109
|
-
### `dub
|
|
138
|
+
### `dub modify` / `dub m`
|
|
110
139
|
|
|
111
|
-
|
|
140
|
+
Amend or create commits on the current branch, then restack descendants.
|
|
112
141
|
|
|
113
142
|
```bash
|
|
114
|
-
|
|
115
|
-
|
|
143
|
+
# amend current commit
|
|
144
|
+
dub modify
|
|
116
145
|
|
|
117
|
-
|
|
118
|
-
-
|
|
119
|
-
- **Idempotent** — safe to run multiple times
|
|
146
|
+
# create a new commit
|
|
147
|
+
dub modify -c -m "fix: ..."
|
|
120
148
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
149
|
+
# interactive staging
|
|
150
|
+
dub modify -p
|
|
151
|
+
|
|
152
|
+
# stage all tracked updates
|
|
153
|
+
dub modify -u
|
|
154
|
+
|
|
155
|
+
# show staged diff before modify
|
|
156
|
+
dub modify -v
|
|
157
|
+
|
|
158
|
+
# show staged + unstaged diff before modify
|
|
159
|
+
dub modify -vv
|
|
160
|
+
|
|
161
|
+
# interactive rebase of this branch's commits
|
|
162
|
+
dub modify --interactive-rebase
|
|
124
163
|
```
|
|
125
164
|
|
|
126
|
-
|
|
165
|
+
Flags:
|
|
166
|
+
- `-a, --all`
|
|
167
|
+
- `-u, --update`
|
|
168
|
+
- `-p, --patch`
|
|
169
|
+
- `-c, --commit`
|
|
170
|
+
- `-e, --edit`
|
|
171
|
+
- `-m, --message <message>` (repeatable)
|
|
172
|
+
- `-v, --verbose` (repeatable)
|
|
173
|
+
- `--interactive-rebase`
|
|
127
174
|
|
|
128
|
-
### `dub
|
|
175
|
+
### `dub checkout` / `dub co`
|
|
129
176
|
|
|
130
|
-
|
|
177
|
+
Checkout a branch directly or use interactive search.
|
|
131
178
|
|
|
132
179
|
```bash
|
|
133
|
-
#
|
|
134
|
-
dub
|
|
180
|
+
# checkout explicit branch
|
|
181
|
+
dub checkout feat/auth-login
|
|
135
182
|
|
|
136
|
-
#
|
|
137
|
-
dub
|
|
138
|
-
```
|
|
183
|
+
# interactive picker
|
|
184
|
+
dub checkout
|
|
139
185
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
- Auto-creates a new stack if the parent isn't already tracked
|
|
143
|
-
- Saves an undo snapshot before any mutation
|
|
186
|
+
# checkout trunk for current tracked stack
|
|
187
|
+
dub checkout --trunk
|
|
144
188
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|---|---|
|
|
148
|
-
| Not initialized | `DubStack is not initialized. Run 'dub init' first.` |
|
|
149
|
-
| Branch already exists | `Branch '<name>' already exists.` |
|
|
150
|
-
| Detached HEAD | `HEAD is detached. Check out a branch first.` |
|
|
189
|
+
# interactive picker including non-tracked local branches
|
|
190
|
+
dub checkout --show-untracked
|
|
151
191
|
|
|
152
|
-
|
|
192
|
+
# interactive picker scoped to current stack
|
|
193
|
+
dub checkout --stack
|
|
194
|
+
```
|
|
153
195
|
|
|
154
|
-
### `dub log`
|
|
196
|
+
### `dub log` / `dub ls` / `dub l`
|
|
155
197
|
|
|
156
|
-
|
|
198
|
+
Render tracked stacks as an ASCII tree.
|
|
157
199
|
|
|
158
200
|
```bash
|
|
159
201
|
dub log
|
|
202
|
+
dub ls
|
|
203
|
+
dub l
|
|
160
204
|
```
|
|
161
205
|
|
|
162
|
-
|
|
206
|
+
### Navigation: `dub up`, `dub down`, `dub top`, `dub bottom`
|
|
163
207
|
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
│ └─ feat/api-endpoint (Current)
|
|
168
|
-
└─ feat/auth
|
|
169
|
-
└─ feat/auth-ui ⚠ (missing)
|
|
170
|
-
```
|
|
208
|
+
```bash
|
|
209
|
+
# move one branch upstack
|
|
210
|
+
dub up
|
|
171
211
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
- Multiple stacks are separated by blank lines
|
|
212
|
+
# move multiple levels upstack
|
|
213
|
+
dub up 2
|
|
214
|
+
# or: dub up --steps 2
|
|
176
215
|
|
|
177
|
-
|
|
216
|
+
# move downstack
|
|
217
|
+
dub down
|
|
218
|
+
dub down 2
|
|
178
219
|
|
|
179
|
-
|
|
220
|
+
# jump to tip branch in current path
|
|
221
|
+
dub top
|
|
180
222
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
dub restack
|
|
223
|
+
# jump to first branch above root
|
|
224
|
+
dub bottom
|
|
185
225
|
```
|
|
186
226
|
|
|
187
|
-
|
|
227
|
+
### `dub info` and `dub branch info`
|
|
188
228
|
|
|
189
|
-
|
|
190
|
-
2. Walks the tree in topological order (parents first)
|
|
191
|
-
3. For each child branch, runs `git rebase --onto <parent_new_tip> <parent_old_tip> <child>`
|
|
192
|
-
4. Skips branches whose parent hasn't moved
|
|
193
|
-
5. Returns you to the branch you started on
|
|
229
|
+
Show tracked metadata for a branch.
|
|
194
230
|
|
|
195
|
-
|
|
231
|
+
```bash
|
|
232
|
+
# current branch
|
|
233
|
+
dub info
|
|
196
234
|
|
|
197
|
-
|
|
235
|
+
# explicit branch
|
|
236
|
+
dub info feat/auth-login
|
|
198
237
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
Resolve conflicts, stage changes, then run: dub restack --continue
|
|
238
|
+
# equivalent legacy style
|
|
239
|
+
dub branch info
|
|
202
240
|
```
|
|
203
241
|
|
|
204
|
-
|
|
242
|
+
### `dub submit` / `dub ss`
|
|
243
|
+
|
|
244
|
+
Push stack branches and create or update PRs.
|
|
205
245
|
|
|
206
246
|
```bash
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
247
|
+
dub submit
|
|
248
|
+
dub ss
|
|
249
|
+
|
|
250
|
+
# preview only
|
|
251
|
+
dub submit --dry-run
|
|
210
252
|
```
|
|
211
253
|
|
|
212
|
-
|
|
254
|
+
### `dub pr [branch-or-number]`
|
|
213
255
|
|
|
214
|
-
|
|
256
|
+
Open a PR in browser via `gh`.
|
|
215
257
|
|
|
258
|
+
```bash
|
|
259
|
+
# current branch PR
|
|
260
|
+
dub pr
|
|
261
|
+
|
|
262
|
+
# explicit branch / PR target
|
|
263
|
+
dub pr feat/auth-login
|
|
264
|
+
dub pr 123
|
|
216
265
|
```
|
|
217
|
-
✔ Stack is already up to date
|
|
218
266
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
267
|
+
### `dub sync`
|
|
268
|
+
|
|
269
|
+
Synchronize tracked branches with remote refs, then optionally restack.
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# sync current stack
|
|
273
|
+
dub sync
|
|
274
|
+
|
|
275
|
+
# sync all tracked stacks
|
|
276
|
+
dub sync --all
|
|
277
|
+
|
|
278
|
+
# non-interactive mode
|
|
279
|
+
dub sync --no-interactive
|
|
280
|
+
|
|
281
|
+
# force destructive sync decisions
|
|
282
|
+
dub sync --force
|
|
283
|
+
|
|
284
|
+
# skip post-sync restack
|
|
285
|
+
dub sync --no-restack
|
|
222
286
|
```
|
|
223
287
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
288
|
+
Current sync behavior includes:
|
|
289
|
+
- fetch tracked refs from `origin`
|
|
290
|
+
- attempt trunk fast-forward (or overwrite with `--force`)
|
|
291
|
+
- cleanup for merged/closed PR branches whose commits are confirmed in trunk
|
|
292
|
+
- reconcile local/remote divergence states per branch
|
|
293
|
+
- restack by default after sync
|
|
294
|
+
|
|
295
|
+
### `dub restack`
|
|
230
296
|
|
|
231
|
-
|
|
297
|
+
Rebase stack branches onto updated parents.
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
dub restack
|
|
301
|
+
|
|
302
|
+
# continue after resolving conflicts
|
|
303
|
+
dub restack --continue
|
|
304
|
+
```
|
|
232
305
|
|
|
233
306
|
### `dub undo`
|
|
234
307
|
|
|
235
|
-
|
|
308
|
+
Undo last `dub create` or `dub restack` operation.
|
|
236
309
|
|
|
237
310
|
```bash
|
|
238
311
|
dub undo
|
|
239
312
|
```
|
|
240
313
|
|
|
241
|
-
|
|
314
|
+
### `dub skills`
|
|
242
315
|
|
|
243
|
-
|
|
244
|
-
- **After `restack`:** Force-resets every rebased branch to its pre-rebase commit, restores state
|
|
316
|
+
Install or remove packaged agent skills.
|
|
245
317
|
|
|
246
|
-
|
|
318
|
+
```bash
|
|
319
|
+
# install all bundled skills
|
|
320
|
+
dub skills add
|
|
247
321
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
322
|
+
# install one skill
|
|
323
|
+
dub skills add dubstack
|
|
324
|
+
|
|
325
|
+
# remove one skill
|
|
326
|
+
dub skills remove dub-flow
|
|
327
|
+
|
|
328
|
+
# preview without changing anything
|
|
329
|
+
dub skills add --dry-run
|
|
330
|
+
dub skills remove --dry-run
|
|
251
331
|
```
|
|
252
332
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
| Nothing to undo | `Nothing to undo.` |
|
|
257
|
-
| Uncommitted changes | `Working tree has uncommitted changes. Commit or stash them before undoing.` |
|
|
333
|
+
## Typical Workflows
|
|
334
|
+
|
|
335
|
+
### Add review feedback to a middle branch
|
|
258
336
|
|
|
259
|
-
|
|
337
|
+
```bash
|
|
338
|
+
# jump to branch needing edits
|
|
339
|
+
dub co feat/auth-login
|
|
260
340
|
|
|
261
|
-
|
|
341
|
+
# edit + amend + restack descendants
|
|
342
|
+
dub m -a -m "fix: address feedback"
|
|
343
|
+
|
|
344
|
+
# resubmit stack
|
|
345
|
+
dub ss
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Sync after trunk moves
|
|
262
349
|
|
|
263
350
|
```bash
|
|
264
|
-
# Start a feature stack off main
|
|
265
351
|
git checkout main
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
dub create feat/api-routes
|
|
270
|
-
# write code, commit
|
|
352
|
+
git pull
|
|
353
|
+
dub sync
|
|
354
|
+
```
|
|
271
355
|
|
|
272
|
-
|
|
273
|
-
# write code, commit
|
|
356
|
+
### Recover from restack conflict
|
|
274
357
|
|
|
275
|
-
|
|
276
|
-
dub log
|
|
277
|
-
# (main)
|
|
278
|
-
# └─ feat/data-layer
|
|
279
|
-
# └─ feat/api-routes
|
|
280
|
-
# └─ feat/frontend (Current)
|
|
281
|
-
|
|
282
|
-
# Later: main gets updated, or you amend feat/data-layer
|
|
283
|
-
git checkout feat/data-layer
|
|
284
|
-
# amend your commits...
|
|
358
|
+
```bash
|
|
285
359
|
dub restack
|
|
286
|
-
#
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
# Oops, that restack went wrong
|
|
291
|
-
dub undo
|
|
292
|
-
# ✔ Undid 'restack': Reset 3 branches to pre-restack state
|
|
360
|
+
# resolve conflicts
|
|
361
|
+
git add <resolved-files>
|
|
362
|
+
dub restack --continue
|
|
293
363
|
```
|
|
294
364
|
|
|
295
|
-
##
|
|
365
|
+
## Troubleshooting
|
|
296
366
|
|
|
297
|
-
|
|
367
|
+
| Problem | What to do |
|
|
368
|
+
|---|---|
|
|
369
|
+
| `gh CLI not found` | Install GitHub CLI: https://cli.github.com |
|
|
370
|
+
| `Not authenticated with GitHub` | Run `gh auth login` |
|
|
371
|
+
| Branch not part of stack | Create via `dub create` or run from tracked branch |
|
|
372
|
+
| Restack conflict | Resolve files, `git add`, `dub restack --continue` |
|
|
373
|
+
| Sync skipped branch | Re-run with `--interactive` or `--force` as appropriate |
|
|
374
|
+
| Wrong operation during create/restack | Use `dub undo` (single-level) |
|
|
298
375
|
|
|
299
|
-
|
|
376
|
+
## State Files
|
|
377
|
+
|
|
378
|
+
DubStack stores local state in your repo:
|
|
379
|
+
|
|
380
|
+
```text
|
|
300
381
|
.git/dubstack/
|
|
301
|
-
├── state.json
|
|
302
|
-
├── undo.json
|
|
303
|
-
└── restack-progress.json
|
|
382
|
+
├── state.json
|
|
383
|
+
├── undo.json
|
|
384
|
+
└── restack-progress.json
|
|
304
385
|
```
|
|
305
386
|
|
|
306
|
-
Nothing is pushed to your remote
|
|
387
|
+
Nothing is pushed to your remote from these files.
|
|
307
388
|
|
|
308
389
|
## Development
|
|
309
390
|
|
|
310
391
|
```bash
|
|
311
|
-
pnpm install
|
|
312
|
-
pnpm
|
|
313
|
-
pnpm
|
|
314
|
-
pnpm
|
|
315
|
-
pnpm
|
|
316
|
-
pnpm
|
|
317
|
-
pnpm checks:fix # auto-fix lint + format issues
|
|
392
|
+
pnpm install
|
|
393
|
+
pnpm test
|
|
394
|
+
pnpm typecheck
|
|
395
|
+
pnpm checks
|
|
396
|
+
pnpm checks:fix
|
|
397
|
+
pnpm build
|
|
318
398
|
```
|
|
319
399
|
|
|
320
400
|
## License
|