vde-worktree 0.0.8 → 0.0.10
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.ja.md +40 -0
- package/README.md +40 -0
- package/completions/fish/vw.fish +55 -13
- package/completions/zsh/_vw +77 -17
- package/dist/index.mjs +518 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -263,6 +263,46 @@ vw extract --current --stash
|
|
|
263
263
|
|
|
264
264
|
- 実装は primary worktree の抽出フローが中心
|
|
265
265
|
|
|
266
|
+
### `absorb`
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
vw absorb feature/foo --allow-agent --allow-unsafe
|
|
270
|
+
vw absorb feature/foo --from feature/foo --keep-stash --allow-agent --allow-unsafe
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
機能:
|
|
274
|
+
|
|
275
|
+
- 非 primary worktree の変更(未コミット含む)を primary worktree に移す
|
|
276
|
+
- source worktree を stash し、primary で checkout 後に stash を apply する
|
|
277
|
+
- `--from` は vw 管理 worktree 名のみ指定可能(`.worktree/` プレフィックスは不可)
|
|
278
|
+
|
|
279
|
+
安全条件:
|
|
280
|
+
|
|
281
|
+
- primary が dirty なら拒否
|
|
282
|
+
- 非TTYでは `--allow-agent` と `--allow-unsafe` の両方が必要
|
|
283
|
+
- `--keep-stash` を付けると apply 後も stash を残す
|
|
284
|
+
|
|
285
|
+
### `unabsorb`
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
vw unabsorb feature/foo --allow-agent --allow-unsafe
|
|
289
|
+
vw unabsorb feature/foo --to feature/foo --keep-stash --allow-agent --allow-unsafe
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
機能:
|
|
293
|
+
|
|
294
|
+
- primary worktree の変更(未コミット含む)を非 primary worktree に戻す
|
|
295
|
+
- primary の変更を stash し、target worktree に stash を apply する
|
|
296
|
+
- `--to` は vw 管理 worktree 名のみ指定可能(`.worktree/` プレフィックスは不可)
|
|
297
|
+
|
|
298
|
+
安全条件:
|
|
299
|
+
|
|
300
|
+
- primary worktree が対象 branch 上である必要がある
|
|
301
|
+
- primary が clean なら拒否
|
|
302
|
+
- target worktree が dirty なら拒否
|
|
303
|
+
- 非TTYでは `--allow-agent` と `--allow-unsafe` の両方が必要
|
|
304
|
+
- `--keep-stash` を付けると apply 後も stash を残す
|
|
305
|
+
|
|
266
306
|
### `use`
|
|
267
307
|
|
|
268
308
|
```bash
|
package/README.md
CHANGED
|
@@ -263,6 +263,46 @@ Current limitation:
|
|
|
263
263
|
|
|
264
264
|
- Implementation currently supports primary worktree extraction flow.
|
|
265
265
|
|
|
266
|
+
### `absorb`
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
vw absorb feature/foo --allow-agent --allow-unsafe
|
|
270
|
+
vw absorb feature/foo --from feature/foo --keep-stash --allow-agent --allow-unsafe
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
What it does:
|
|
274
|
+
|
|
275
|
+
- Moves changes from non-primary worktree to primary worktree, including uncommitted files
|
|
276
|
+
- Stashes source worktree changes, checks out branch in primary, then applies stash
|
|
277
|
+
- `--from` accepts vw-managed worktree name only (`.worktree/` prefix is rejected)
|
|
278
|
+
|
|
279
|
+
Safety:
|
|
280
|
+
|
|
281
|
+
- Rejects dirty primary worktree
|
|
282
|
+
- In non-TTY mode, requires `--allow-agent` and `--allow-unsafe`
|
|
283
|
+
- `--keep-stash` keeps the stash entry after apply for rollback/debugging
|
|
284
|
+
|
|
285
|
+
### `unabsorb`
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
vw unabsorb feature/foo --allow-agent --allow-unsafe
|
|
289
|
+
vw unabsorb feature/foo --to feature/foo --keep-stash --allow-agent --allow-unsafe
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
What it does:
|
|
293
|
+
|
|
294
|
+
- Pushes changes from primary worktree to non-primary worktree, including uncommitted files
|
|
295
|
+
- Stashes primary worktree changes, applies stash in target worktree
|
|
296
|
+
- `--to` accepts vw-managed worktree name only (`.worktree/` prefix is rejected)
|
|
297
|
+
|
|
298
|
+
Safety:
|
|
299
|
+
|
|
300
|
+
- Requires primary worktree to be on target branch
|
|
301
|
+
- Rejects clean primary worktree
|
|
302
|
+
- Rejects dirty target worktree
|
|
303
|
+
- In non-TTY mode, requires `--allow-agent` and `--allow-unsafe`
|
|
304
|
+
- `--keep-stash` keeps the stash entry after apply for rollback/debugging
|
|
305
|
+
|
|
266
306
|
### `use`
|
|
267
307
|
|
|
268
308
|
```bash
|
package/completions/fish/vw.fish
CHANGED
|
@@ -88,6 +88,45 @@ for (const worktree of worktrees) {
|
|
|
88
88
|
' 2>/dev/null
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
+
function __vw_managed_worktree_names_with_meta
|
|
92
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>/dev/null; or return 0
|
|
93
|
+
set -l vw_bin (__vw_current_bin)
|
|
94
|
+
test -n "$vw_bin"; or return 0
|
|
95
|
+
|
|
96
|
+
command $vw_bin list --json 2>/dev/null | command node -e '
|
|
97
|
+
const fs = require("fs")
|
|
98
|
+
const path = require("path")
|
|
99
|
+
const toFlag = (value) => {
|
|
100
|
+
if (value === true) return "yes"
|
|
101
|
+
if (value === false) return "no"
|
|
102
|
+
return "unknown"
|
|
103
|
+
}
|
|
104
|
+
let payload
|
|
105
|
+
try {
|
|
106
|
+
payload = JSON.parse(fs.readFileSync(0, "utf8"))
|
|
107
|
+
} catch {
|
|
108
|
+
process.exit(0)
|
|
109
|
+
}
|
|
110
|
+
const repoRoot = typeof payload?.repoRoot === "string" ? payload.repoRoot : ""
|
|
111
|
+
if (repoRoot.length === 0) process.exit(0)
|
|
112
|
+
const worktreeRoot = path.join(repoRoot, ".worktree")
|
|
113
|
+
const worktrees = Array.isArray(payload.worktrees) ? payload.worktrees : []
|
|
114
|
+
for (const worktree of worktrees) {
|
|
115
|
+
if (typeof worktree?.path !== "string" || worktree.path.length === 0) continue
|
|
116
|
+
const rel = path.relative(worktreeRoot, worktree.path)
|
|
117
|
+
if (!rel || rel === "." || rel === ".." || rel.startsWith(`..${path.sep}`)) continue
|
|
118
|
+
const name = rel.split(path.sep).join("/")
|
|
119
|
+
const branch = typeof worktree?.branch === "string" && worktree.branch.length > 0 ? worktree.branch : "(detached)"
|
|
120
|
+
const merged = toFlag(worktree?.merged?.overall)
|
|
121
|
+
const dirty = worktree?.dirty === true ? "yes" : "no"
|
|
122
|
+
const locked = worktree?.locked?.value === true ? "yes" : "no"
|
|
123
|
+
const summary = `branch=${branch} merged=${merged} dirty=${dirty} locked=${locked}`
|
|
124
|
+
const sanitized = summary.replace(/[\t\r\n]+/g, " ").trim()
|
|
125
|
+
process.stdout.write(`${name}\t${sanitized}\n`)
|
|
126
|
+
}
|
|
127
|
+
' 2>/dev/null
|
|
128
|
+
end
|
|
129
|
+
|
|
91
130
|
function __vw_use_candidates_with_meta
|
|
92
131
|
begin
|
|
93
132
|
__vw_worktree_branches
|
|
@@ -95,16 +134,6 @@ function __vw_use_candidates_with_meta
|
|
|
95
134
|
end | sort -u
|
|
96
135
|
end
|
|
97
136
|
|
|
98
|
-
function __vw_local_branches
|
|
99
|
-
command git rev-parse --is-inside-work-tree >/dev/null 2>/dev/null; or return 0
|
|
100
|
-
command git for-each-ref --format='%(refname:short)' refs/heads 2>/dev/null | sort -u
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
function __vw_switch_branches
|
|
104
|
-
__vw_worktree_branches
|
|
105
|
-
__vw_local_branches
|
|
106
|
-
end
|
|
107
|
-
|
|
108
137
|
function __vw_remote_branches
|
|
109
138
|
command git rev-parse --is-inside-work-tree >/dev/null 2>/dev/null; or return 0
|
|
110
139
|
command git for-each-ref --format='%(refname:short)' refs/remotes 2>/dev/null \
|
|
@@ -120,7 +149,7 @@ function __vw_hook_names
|
|
|
120
149
|
end
|
|
121
150
|
end
|
|
122
151
|
|
|
123
|
-
set -l __vw_commands init list status path new switch mv del gone get extract use exec invoke copy link lock unlock cd completion help
|
|
152
|
+
set -l __vw_commands init list status path new switch mv del gone get extract absorb unabsorb use exec invoke copy link lock unlock cd completion help
|
|
124
153
|
|
|
125
154
|
for __vw_bin in vw vde-worktree
|
|
126
155
|
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a init -d "Initialize directories, hooks, and managed exclude entries"
|
|
@@ -134,6 +163,8 @@ for __vw_bin in vw vde-worktree
|
|
|
134
163
|
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a gone -d "Bulk cleanup by safety-filtered candidate selection"
|
|
135
164
|
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a get -d "Fetch remote branch and attach worktree"
|
|
136
165
|
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a extract -d "Extract current primary branch into .worktree"
|
|
166
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a absorb -d "Bring non-primary worktree changes into primary worktree"
|
|
167
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a unabsorb -d "Push primary worktree changes into non-primary worktree"
|
|
137
168
|
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a use -d "Checkout target branch in primary worktree"
|
|
138
169
|
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a exec -d "Run command in target branch worktree"
|
|
139
170
|
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a invoke -d "Manually run hook script"
|
|
@@ -157,10 +188,11 @@ for __vw_bin in vw vde-worktree
|
|
|
157
188
|
|
|
158
189
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from status" -a "(__vw_worktree_candidates_with_meta)"
|
|
159
190
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from path" -a "(__vw_worktree_candidates_with_meta)"
|
|
160
|
-
complete -c $__vw_bin -n "__fish_seen_subcommand_from switch" -a "(
|
|
161
|
-
complete -c $__vw_bin -n "__fish_seen_subcommand_from mv" -a "(__vw_local_branches)"
|
|
191
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from switch" -a "(__vw_worktree_candidates_with_meta)"
|
|
162
192
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from del" -a "(__vw_worktree_candidates_with_meta)"
|
|
163
193
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from get" -a "(__vw_remote_branches)"
|
|
194
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from absorb" -a "(__vw_worktree_candidates_with_meta)"
|
|
195
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from unabsorb" -a "(__vw_worktree_candidates_with_meta)"
|
|
164
196
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from use" -a "(__vw_use_candidates_with_meta)"
|
|
165
197
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from exec" -a "(__vw_worktree_candidates_with_meta)"
|
|
166
198
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from invoke" -a "(__vw_hook_names)"
|
|
@@ -181,6 +213,16 @@ for __vw_bin in vw vde-worktree
|
|
|
181
213
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from extract" -l from -r -d "Path used by extract --from"
|
|
182
214
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from extract" -l stash -d "Allow stash when dirty"
|
|
183
215
|
|
|
216
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from absorb" -l from -r -a "(__vw_managed_worktree_names_with_meta)" -d "Source managed worktree name"
|
|
217
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from absorb" -l keep-stash -d "Keep stash entry after absorb"
|
|
218
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from absorb" -l allow-agent -d "Allow non-TTY execution for absorb"
|
|
219
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from absorb" -l allow-unsafe -d "Allow unsafe behavior in non-TTY mode"
|
|
220
|
+
|
|
221
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from unabsorb" -l to -r -a "(__vw_managed_worktree_names_with_meta)" -d "Target managed worktree name"
|
|
222
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from unabsorb" -l keep-stash -d "Keep stash entry after unabsorb"
|
|
223
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from unabsorb" -l allow-agent -d "Allow non-TTY execution for unabsorb"
|
|
224
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from unabsorb" -l allow-unsafe -d "Allow unsafe behavior in non-TTY mode"
|
|
225
|
+
|
|
184
226
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from use" -l allow-agent -d "Allow non-TTY execution for use"
|
|
185
227
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from use" -l allow-shared -d "Allow checkout when branch is attached by another worktree"
|
|
186
228
|
complete -c $__vw_bin -n "__fish_seen_subcommand_from use" -l allow-unsafe -d "Allow unsafe behavior in non-TTY mode"
|
package/completions/zsh/_vw
CHANGED
|
@@ -65,9 +65,43 @@ for (const worktree of worktrees) {
|
|
|
65
65
|
' 2>/dev/null
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
_vw_managed_worktree_name_rows_raw() {
|
|
69
69
|
command git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
|
|
70
|
-
|
|
70
|
+
local vw_bin="${words[1]:-vw}"
|
|
71
|
+
command -v "$vw_bin" >/dev/null 2>&1 || return 0
|
|
72
|
+
|
|
73
|
+
command "$vw_bin" list --json 2>/dev/null | command node -e '
|
|
74
|
+
const fs = require("fs")
|
|
75
|
+
const path = require("path")
|
|
76
|
+
const toFlag = (value) => {
|
|
77
|
+
if (value === true) return "yes"
|
|
78
|
+
if (value === false) return "no"
|
|
79
|
+
return "unknown"
|
|
80
|
+
}
|
|
81
|
+
let payload
|
|
82
|
+
try {
|
|
83
|
+
payload = JSON.parse(fs.readFileSync(0, "utf8"))
|
|
84
|
+
} catch {
|
|
85
|
+
process.exit(0)
|
|
86
|
+
}
|
|
87
|
+
const repoRoot = typeof payload?.repoRoot === "string" ? payload.repoRoot : ""
|
|
88
|
+
if (repoRoot.length === 0) process.exit(0)
|
|
89
|
+
const worktreeRoot = path.join(repoRoot, ".worktree")
|
|
90
|
+
const worktrees = Array.isArray(payload.worktrees) ? payload.worktrees : []
|
|
91
|
+
for (const worktree of worktrees) {
|
|
92
|
+
if (typeof worktree?.path !== "string" || worktree.path.length === 0) continue
|
|
93
|
+
const rel = path.relative(worktreeRoot, worktree.path)
|
|
94
|
+
if (!rel || rel === "." || rel === ".." || rel.startsWith(`..${path.sep}`)) continue
|
|
95
|
+
const name = rel.split(path.sep).join("/")
|
|
96
|
+
const branch = typeof worktree?.branch === "string" && worktree.branch.length > 0 ? worktree.branch : "(detached)"
|
|
97
|
+
const merged = toFlag(worktree?.merged?.overall)
|
|
98
|
+
const dirty = worktree?.dirty === true ? "yes" : "no"
|
|
99
|
+
const locked = worktree?.locked?.value === true ? "yes" : "no"
|
|
100
|
+
const summary = `branch=${branch} merged=${merged} dirty=${dirty} locked=${locked}`
|
|
101
|
+
const sanitized = summary.replace(/[\t\r\n]+/g, " ").trim()
|
|
102
|
+
process.stdout.write(`${name}\t${sanitized}\n`)
|
|
103
|
+
}
|
|
104
|
+
' 2>/dev/null
|
|
71
105
|
}
|
|
72
106
|
|
|
73
107
|
_vw_remote_branches_raw() {
|
|
@@ -147,20 +181,28 @@ _vw_complete_use_branches() {
|
|
|
147
181
|
_vw_complete_worktree_branches
|
|
148
182
|
}
|
|
149
183
|
|
|
150
|
-
|
|
151
|
-
local -a
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
184
|
+
_vw_complete_managed_worktree_names() {
|
|
185
|
+
local -a rows names descriptions
|
|
186
|
+
local row name summary
|
|
187
|
+
rows=("${(@f)$(_vw_managed_worktree_name_rows_raw)}")
|
|
155
188
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
"${
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
189
|
+
for row in "${rows[@]}"; do
|
|
190
|
+
name="${row%%$'\t'*}"
|
|
191
|
+
summary="${row#*$'\t'}"
|
|
192
|
+
if [[ -z "${name}" ]]; then
|
|
193
|
+
continue
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
names+=("${name}")
|
|
197
|
+
descriptions+=("${summary}")
|
|
198
|
+
done
|
|
199
|
+
|
|
200
|
+
if (( ${#names} > 0 )); then
|
|
201
|
+
compadd -Ql -d descriptions -a names
|
|
202
|
+
return 0
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
_message "no managed-worktree-name candidates"
|
|
164
206
|
}
|
|
165
207
|
|
|
166
208
|
_vw_complete_remote_branches() {
|
|
@@ -193,6 +235,8 @@ _vw() {
|
|
|
193
235
|
"gone:Bulk cleanup by safety-filtered candidate selection"
|
|
194
236
|
"get:Fetch remote branch and attach worktree"
|
|
195
237
|
"extract:Extract current primary branch into .worktree"
|
|
238
|
+
"absorb:Bring non-primary worktree changes into primary worktree"
|
|
239
|
+
"unabsorb:Push primary worktree changes into non-primary worktree"
|
|
196
240
|
"use:Checkout target branch in primary worktree"
|
|
197
241
|
"exec:Run command in target branch worktree"
|
|
198
242
|
"invoke:Manually run hook script"
|
|
@@ -240,11 +284,11 @@ _vw() {
|
|
|
240
284
|
;;
|
|
241
285
|
switch)
|
|
242
286
|
_arguments \
|
|
243
|
-
"1:branch:
|
|
287
|
+
"1:branch:_vw_complete_worktree_branches_with_meta"
|
|
244
288
|
;;
|
|
245
289
|
mv)
|
|
246
290
|
_arguments \
|
|
247
|
-
"1:new-branch:
|
|
291
|
+
"1:new-branch:"
|
|
248
292
|
;;
|
|
249
293
|
del)
|
|
250
294
|
_arguments \
|
|
@@ -270,6 +314,22 @@ _vw() {
|
|
|
270
314
|
"--from[Path used by extract --from]:path:_files" \
|
|
271
315
|
"--stash[Allow stash when dirty]"
|
|
272
316
|
;;
|
|
317
|
+
absorb)
|
|
318
|
+
_arguments \
|
|
319
|
+
"1:branch:_vw_complete_worktree_branches_with_meta" \
|
|
320
|
+
"--from[Source managed worktree name]:worktree-name:_vw_complete_managed_worktree_names" \
|
|
321
|
+
"--keep-stash[Keep stash entry after absorb]" \
|
|
322
|
+
"--allow-agent[Allow non-TTY execution for absorb]" \
|
|
323
|
+
"--allow-unsafe[Allow unsafe behavior in non-TTY mode]"
|
|
324
|
+
;;
|
|
325
|
+
unabsorb)
|
|
326
|
+
_arguments \
|
|
327
|
+
"1:branch:_vw_complete_worktree_branches_with_meta" \
|
|
328
|
+
"--to[Target managed worktree name]:worktree-name:_vw_complete_managed_worktree_names" \
|
|
329
|
+
"--keep-stash[Keep stash entry after unabsorb]" \
|
|
330
|
+
"--allow-agent[Allow non-TTY execution for unabsorb]" \
|
|
331
|
+
"--allow-unsafe[Allow unsafe behavior in non-TTY mode]"
|
|
332
|
+
;;
|
|
273
333
|
use)
|
|
274
334
|
_arguments \
|
|
275
335
|
"1:branch:_vw_complete_use_branches" \
|