1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
#compdef wt
_wt() {
local curcontext="$curcontext" state line
typeset -A opt_args
_arguments -C \
'1: :->command' \
'*: :->args' \
&& return 0
case $state in
command)
local -a commands
commands=(
'list:List worktrees'
'ls:List worktrees'
'l:List worktrees'
'create:Create/switch to worktree'
'c:Create/switch to worktree'
'delete:Delete worktree'
'rm:Delete worktree'
'd:Delete worktree'
'sync:Re-sync symlinks from main worktree'
's:Re-sync symlinks from main worktree'
'prune:Delete merged and safe detached worktrees'
'p:Delete merged and safe detached worktrees'
'edit:Open worktree in editor'
'e:Open worktree in editor'
'help:Show help'
'-v:List with details'
'-vv:List with details and symlinks'
)
_describe -t commands 'command' commands
# Also complete branch names for direct create
local -a branches
branches=(${(f)"$(git for-each-ref --format='%(refname:short)' refs/heads/ 2>/dev/null)"})
_describe -t branches 'branch' branches
;;
args)
case "${words[2]}" in
c|create)
# Complete branches for create
local -a branches worktrees
worktrees=(${(f)"$(git worktree list --porcelain 2>/dev/null | awk '/^branch / {sub(/^refs\/heads\//, "", $2); print $2}')"})
branches=(${(f)"$(git for-each-ref --format='%(refname:short)' refs/heads/ 2>/dev/null)"})
local -a all_branches
all_branches=("${(@u)worktrees}" "${(@u)branches}")
_describe -t branches 'branch' all_branches
_message 'branch name (existing or new)'
;;
d|delete|rm|remove)
# Complete existing worktrees for delete
local -a worktrees
worktrees=(${(f)"$(git worktree list --porcelain 2>/dev/null | awk '
BEGIN { RS=""; FS="\n" }
{
path=""; branch="";
for (i=1; i<=NF; i++) {
if ($i ~ /^worktree /) path=substr($i,10)
else if ($i ~ /^branch /) {
branch=substr($i,8)
sub(/^refs\/heads\//, "", branch)
}
}
if (path ~ /\.worktrees/ && branch != "") print branch
}
')"})
if (( ${#worktrees} > 0 )); then
_describe -t worktrees 'worktree' worktrees
fi
;;
s|sync)
_arguments \
'(-a --all)'{-a,--all}'[Sync all worktrees]'
# Complete worktree branch names
local -a worktrees
worktrees=(${(f)"$(git worktree list --porcelain 2>/dev/null | awk '
BEGIN { RS=""; FS="\n" }
{
path=""; branch="";
for (i=1; i<=NF; i++) {
if ($i ~ /^worktree /) path=substr($i,10)
else if ($i ~ /^branch /) {
branch=substr($i,8)
sub(/^refs\/heads\//, "", branch)
}
}
if (path ~ /\.worktrees/ && branch != "") print branch
}
')"})
if (( ${#worktrees} > 0 )); then
_describe -t worktrees 'worktree' worktrees
fi
;;
p|prune)
_arguments \
'(-n --dry-run)'{-n,--dry-run}'[Show what would be pruned]' \
'(-f --force)'{-f,--force}'[Skip confirmation prompt and allow dirty/unreferenced detached removal]' \
'(-d --detached)'{-d,--detached}'[Also show dirty/unreferenced detached worktrees]'
;;
e|edit)
# Complete existing worktrees for edit
local -a worktrees
worktrees=(${(f)"$(git worktree list --porcelain 2>/dev/null | awk '
BEGIN { RS=""; FS="\n" }
{
path=""; branch="";
for (i=1; i<=NF; i++) {
if ($i ~ /^worktree /) path=substr($i,10)
else if ($i ~ /^branch /) {
branch=substr($i,8)
sub(/^refs\/heads\//, "", branch)
}
}
if (branch != "") print branch
}
')"})
if (( ${#worktrees} > 0 )); then
_describe -t worktrees 'worktree' worktrees
fi
;;
l|list|ls|-v|-vv)
_arguments \
'(-v --verbose -vv)'{-v,--verbose}'[Show details]' \
'(-v --verbose -vv)-vv[Show details and symlinks]'
;;
esac
;;
esac
}
_wt "$@"
|