wtcode 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl
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.
- wtcode/__init__.py +1 -1
- wtcode/wtcode.sh +53 -14
- {wtcode-0.1.2.dist-info → wtcode-0.1.4.dist-info}/METADATA +7 -3
- wtcode-0.1.4.dist-info/RECORD +9 -0
- wtcode-0.1.2.dist-info/RECORD +0 -9
- {wtcode-0.1.2.dist-info → wtcode-0.1.4.dist-info}/WHEEL +0 -0
- {wtcode-0.1.2.dist-info → wtcode-0.1.4.dist-info}/entry_points.txt +0 -0
- {wtcode-0.1.2.dist-info → wtcode-0.1.4.dist-info}/licenses/LICENSE +0 -0
- {wtcode-0.1.2.dist-info → wtcode-0.1.4.dist-info}/top_level.txt +0 -0
wtcode/__init__.py
CHANGED
wtcode/wtcode.sh
CHANGED
|
@@ -8,8 +8,15 @@ shopt -s extglob
|
|
|
8
8
|
${WTCODE_DEBUG:+set -x}
|
|
9
9
|
|
|
10
10
|
--msg() { echo "wtcode: $*" >&2; }
|
|
11
|
+
--sanitize-branch-name() {
|
|
12
|
+
printf '%s' "$1" |
|
|
13
|
+
tr '[:upper:]' '[:lower:]' | # lowercase
|
|
14
|
+
sed 's/[^a-z0-9/_-]/-/g' | # replace non-alnum to hyphens
|
|
15
|
+
sed 's/--*/-/g' | # collapse consecutive hyphens
|
|
16
|
+
sed 's/^-//; s/-$//' # trim leading/trailing hyphens
|
|
17
|
+
}
|
|
11
18
|
|
|
12
|
-
WTCODE_VERSION=0.1.
|
|
19
|
+
WTCODE_VERSION=0.1.4
|
|
13
20
|
--version() { echo "wtcode $WTCODE_VERSION"; }
|
|
14
21
|
--help() {
|
|
15
22
|
cat <<USAGE
|
|
@@ -20,8 +27,9 @@ Usage: wtcode [BRANCH] [CMD [CMD-ARGS...]]
|
|
|
20
27
|
|
|
21
28
|
BRANCH Git branch or worktree name to switch to.
|
|
22
29
|
If omitted and fzf is available, interactively select one.
|
|
23
|
-
|
|
24
|
-
(use multiple colons to avoid fzf matching, e.g., :::my-branch
|
|
30
|
+
Surround with ':' to force creating a new branch
|
|
31
|
+
(use multiple colons to avoid fzf matching, e.g., :::my-branch
|
|
32
|
+
or my-branch:::).
|
|
25
33
|
|
|
26
34
|
CMD Command to launch in the worktree (default: \$WTCODE_CMD,
|
|
27
35
|
or first available of: ${WTCODE_CMDS_TO_TRY[*]}, \$SHELL).
|
|
@@ -120,20 +128,20 @@ WTCODE_CMDS_TO_TRY=(
|
|
|
120
128
|
exit 1
|
|
121
129
|
fi
|
|
122
130
|
|
|
123
|
-
#
|
|
124
|
-
#
|
|
131
|
+
# leading or trailing ':' forces new branch creation
|
|
132
|
+
# multiple colons (e.g., :::my-branch or my-branch:::) help avoid fzf matching
|
|
125
133
|
local force_new_branch=false
|
|
126
|
-
if [[ $branch_name == :* ]]; then
|
|
134
|
+
if [[ $branch_name == :* || $branch_name == *: ]]; then
|
|
127
135
|
force_new_branch=true
|
|
128
136
|
branch_name=${branch_name##+(:)}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
)
|
|
137
|
+
branch_name=${branch_name%%+(:)}
|
|
138
|
+
: ${branch_name:?non-empty branch name required around ':'}
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# sanitize free-form text into a valid git branch name
|
|
142
|
+
# (skip if it already matches an existing branch/ref to preserve case)
|
|
143
|
+
if $force_new_branch || ! git rev-parse --verify "$branch_name" &>/dev/null; then
|
|
144
|
+
branch_name=$(--sanitize-branch-name "$branch_name")
|
|
137
145
|
: ${branch_name:?branch name is empty after sanitization}
|
|
138
146
|
fi
|
|
139
147
|
|
|
@@ -149,6 +157,19 @@ WTCODE_CMDS_TO_TRY=(
|
|
|
149
157
|
done
|
|
150
158
|
fi
|
|
151
159
|
|
|
160
|
+
# if the branch is already checked out on a worktree, use that worktree
|
|
161
|
+
# regardless of its directory name — avoids "already checked out" failures
|
|
162
|
+
# when branches and worktree directories have drifted apart (e.g., after
|
|
163
|
+
# something like claude ran `git checkout` inside a worktree)
|
|
164
|
+
if ! $force_new_branch && [[ -z ${remote_branch-} ]]; then
|
|
165
|
+
local existing_worktree
|
|
166
|
+
existing_worktree=$(git for-each-ref --format='%(worktreepath)' "refs/heads/$branch_name" 2>/dev/null)
|
|
167
|
+
if [[ -n $existing_worktree ]]; then
|
|
168
|
+
--msg "branch '$branch_name' is checked out at: $existing_worktree"
|
|
169
|
+
cd "$existing_worktree"
|
|
170
|
+
return 0
|
|
171
|
+
fi
|
|
172
|
+
fi
|
|
152
173
|
|
|
153
174
|
# 2. create or switch to the worktree
|
|
154
175
|
cd "$(git rev-parse --show-toplevel)"
|
|
@@ -161,6 +182,24 @@ WTCODE_CMDS_TO_TRY=(
|
|
|
161
182
|
)}
|
|
162
183
|
|
|
163
184
|
local worktree_path="$GIT_WORKTREE_ROOT"/"$branch_name"
|
|
185
|
+
|
|
186
|
+
# if the default worktree directory exists but holds a different branch
|
|
187
|
+
# (e.g., something like claude swapped branches with `git checkout`), pick
|
|
188
|
+
# a fresh numbered suffix instead of stealing it. branch-is-checked-out
|
|
189
|
+
# case is already handled above, so we only need to check the default path.
|
|
190
|
+
if [[ -e "$worktree_path"/.git ]]; then
|
|
191
|
+
local existing_branch
|
|
192
|
+
existing_branch=$(git -C "$worktree_path" branch --show-current 2>/dev/null)
|
|
193
|
+
if [[ -n $existing_branch && $existing_branch != "$branch_name" ]]; then
|
|
194
|
+
--msg "$worktree_path holds branch '$existing_branch'; picking a new path for '$branch_name'"
|
|
195
|
+
local n=2
|
|
196
|
+
while [[ -e "$GIT_WORKTREE_ROOT/$branch_name-$n" ]]; do
|
|
197
|
+
n=$((n+1))
|
|
198
|
+
done
|
|
199
|
+
worktree_path="$GIT_WORKTREE_ROOT/$branch_name-$n"
|
|
200
|
+
fi
|
|
201
|
+
fi
|
|
202
|
+
|
|
164
203
|
if [[ -e "$worktree_path"/.git ]]; then
|
|
165
204
|
--msg "using existing worktree: $worktree_path"
|
|
166
205
|
elif [[ -n ${remote_branch-} ]] && ! git rev-parse --verify "refs/heads/$branch_name" &>/dev/null; then
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wtcode
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Launch your favorite code tool in a git worktree
|
|
5
5
|
Author-email: Jaeho Shin <netj@sparcs.org>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -18,7 +18,7 @@ Dynamic: license-file
|
|
|
18
18
|
|
|
19
19
|
# wtcode
|
|
20
20
|
|
|
21
|
-
**
|
|
21
|
+
**Effortlessly launch your favorite code tool in a git worktree.**
|
|
22
22
|
|
|
23
23
|
*worktree code* / *what-the-code* -- streamlines git worktree selection, creation, and launching tools like [Claude Code](https://claude.ai/code), [lazygit](https://github.com/jesseduffield/lazygit), your editor, or any command.
|
|
24
24
|
|
|
@@ -56,10 +56,13 @@ ln -s "$PWD/wtcode/wtcode.sh" /usr/local/bin/wtcode
|
|
|
56
56
|
|
|
57
57
|
```
|
|
58
58
|
wtcode [BRANCH] [CMD [CMD-ARGS...]]
|
|
59
|
+
wtcode --exec CMD [CMD-ARGS...]
|
|
59
60
|
```
|
|
60
61
|
|
|
61
|
-
- **`BRANCH`** -- Git branch or worktree name. If omitted and [fzf](https://github.com/junegunn/fzf) is available, interactively select one.
|
|
62
|
+
- **`BRANCH`** -- Git branch or worktree name. If omitted and [fzf](https://github.com/junegunn/fzf) is available, interactively select one. Surround with `:` to create a new branch (use `:::name` or `name:::` to avoid fzf matching the colons).
|
|
62
63
|
- **`CMD`** -- Command to launch in the worktree. Defaults to `$WTCODE_CMD`, or the first available of: `claude`, `aider`, `codex`, `$SHELL`.
|
|
64
|
+
- **`--exec`** -- Skip the branch argument; select interactively via fzf, then launch `CMD`.
|
|
65
|
+
- **`--help`** / **`--version`** -- Show help or version info.
|
|
63
66
|
|
|
64
67
|
### Examples
|
|
65
68
|
|
|
@@ -67,6 +70,7 @@ wtcode [BRANCH] [CMD [CMD-ARGS...]]
|
|
|
67
70
|
wtcode feature-x # launch default tool in feature-x worktree
|
|
68
71
|
wtcode feature-x lazygit # launch lazygit
|
|
69
72
|
wtcode feature-x claude --resume # launch claude with flags
|
|
73
|
+
wtcode --exec claude --resume # select interactively, launch claude --resume
|
|
70
74
|
wtcode :new-feature # create new branch and worktree
|
|
71
75
|
wtcode # interactive branch selection via fzf
|
|
72
76
|
WTCODE_CMD=cursor wtcode feature # use cursor as default tool
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
wtcode/__init__.py,sha256=0ZQh71koVy1Uu4uc2158fJIamOMkJ-ER-gHxB2OBb7s,89
|
|
2
|
+
wtcode/__main__.py,sha256=hOvSYANO-q_rf2yy-AQoEOr18KFRSOF8Ezosf8eeFmM,335
|
|
3
|
+
wtcode/wtcode.sh,sha256=vhEWnZhhSpOXxaGA4WnOAYotb0opgdySAfZVR4LDyRc,11604
|
|
4
|
+
wtcode-0.1.4.dist-info/licenses/LICENSE,sha256=MV9gr1nAVj5R60EM2BQuBhBxCG5V9ulX6-Ep_-LcLqA,1067
|
|
5
|
+
wtcode-0.1.4.dist-info/METADATA,sha256=nZZUoSmKYRD3qyc08HFftXAkmjwjiPopBiluwxPZtoc,3477
|
|
6
|
+
wtcode-0.1.4.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
7
|
+
wtcode-0.1.4.dist-info/entry_points.txt,sha256=QkSPHU86FQa-ujQk07fF4sX4DBQgWzDtgusop4AA5bc,48
|
|
8
|
+
wtcode-0.1.4.dist-info/top_level.txt,sha256=oftTSYYjDMqt33wa0c9MC15KuQ3eyRyoTLXy3PdkVfE,7
|
|
9
|
+
wtcode-0.1.4.dist-info/RECORD,,
|
wtcode-0.1.2.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
wtcode/__init__.py,sha256=A7RqB4aySmZ4zC0GmQ3cn3i2z8NUJGh8WY-8JAvivfE,89
|
|
2
|
-
wtcode/__main__.py,sha256=hOvSYANO-q_rf2yy-AQoEOr18KFRSOF8Ezosf8eeFmM,335
|
|
3
|
-
wtcode/wtcode.sh,sha256=eBIC58ZxYjNznxiyi3Lg8_H931e0dfqrGwibsWRq9XA,9844
|
|
4
|
-
wtcode-0.1.2.dist-info/licenses/LICENSE,sha256=MV9gr1nAVj5R60EM2BQuBhBxCG5V9ulX6-Ep_-LcLqA,1067
|
|
5
|
-
wtcode-0.1.2.dist-info/METADATA,sha256=Ee8djPN9Zq0fmyhmJt8LsjCjebSQJsBDPF-CTds3wJo,3180
|
|
6
|
-
wtcode-0.1.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
7
|
-
wtcode-0.1.2.dist-info/entry_points.txt,sha256=QkSPHU86FQa-ujQk07fF4sX4DBQgWzDtgusop4AA5bc,48
|
|
8
|
-
wtcode-0.1.2.dist-info/top_level.txt,sha256=oftTSYYjDMqt33wa0c9MC15KuQ3eyRyoTLXy3PdkVfE,7
|
|
9
|
-
wtcode-0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|