Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Then reload your shell (`source ~/.zshrc`) or open a new terminal.
```sh
wt # list all worktrees
wt <name> # cd into worktree by branch name
wt ~ # cd to the repo root (also: wt root)
wt mk <branch> # create worktree in .claude/worktrees/<branch> and cd into it
wt mk <branch> <path> # create worktree at a specific path and cd into it
wt rm <name> # remove a worktree
Expand Down
33 changes: 33 additions & 0 deletions test/cd.bats
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,36 @@ teardown() { wt_common_teardown; }
[ "$status" -eq 1 ]
[[ "$output" == *"no worktree matching"* ]]
}

@test "wt ~ goes to the repo root" {
cd "$TEST_REPO-feature"
_wt_cd "~"
[ "$PWD" = "$TEST_REPO" ]
}

@test "wt ~ works after the shell has expanded it to \$HOME" {
cd "$TEST_REPO-feature"
_wt_cd "$HOME"
[ "$PWD" = "$TEST_REPO" ]
}

@test "wt root goes to the repo root" {
cd "$TEST_REPO-other"
wt root
[ "$PWD" = "$TEST_REPO" ]
}

@test "a worktree named root still wins over the repo root" {
git -C "$TEST_REPO" worktree add -q "$TEST_REPO-root" -b root
cd "$TEST_REPO-feature"
_wt_cd root
[ "$PWD" = "$TEST_REPO-root" ]
cd "$TEST_REPO"
git worktree remove "$TEST_REPO-root"
}

@test "wt ~ outside a repo fails rather than going home" {
cd "$(mktemp -d)"
run _wt_cd "~"
[ "$status" -ne 0 ]
}
Comment thread
stilliard marked this conversation as resolved.
23 changes: 17 additions & 6 deletions wt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,21 @@ _wt_claude_rm_sessions() {
return "$rc"
}

# navigate to a worktree by branch name or directory basename
# navigate to a worktree by branch name or directory basename; ~ (or root) goes
# to the repo root. The shell expands a bare ~ before wt sees it, so $HOME counts
# as ~ too. A real worktree still wins, so a branch named "root" keeps working.
_wt_cd() {
local target
target=$(_wt_resolve "${1?usage: wt <name>}")
[ -z "$target" ] && { echo "wt: no worktree matching '$1'" >&2; return 1; }
local name="${1?usage: wt <name>}" target root
if [ "$name" != "~" ] && { [ -z "$HOME" ] || [ "$name" != "$HOME" ]; }; then
target=$(_wt_resolve "$name")
fi
if [ -z "$target" ]; then
case "$name" in
"~"|root|"${HOME:-~}") root=$(_wt_root) || return 1; cd "$root"; return ;;
esac
Comment thread
stilliard marked this conversation as resolved.
echo "wt: no worktree matching '$name'" >&2
return 1
fi
cd "$target"
}

Expand Down Expand Up @@ -420,6 +430,7 @@ Usage: wt [command] [args]
Commands:
wt list all worktrees
wt <name> cd into worktree by branch name
wt ~ cd to the repo root (also: wt root)
wt cd <name> cd into worktree (explicit form)
wt ls [opts] list worktrees (same as bare wt)
wt mk <branch> [path] [opts] create worktree (default: .claude/worktrees/<branch>)
Expand Down Expand Up @@ -503,7 +514,7 @@ if [ -n "$ZSH_VERSION" ]; then
local -a matches
# l:|=* matches the typed text anywhere in a candidate
if [ $CURRENT -eq 2 ]; then
matches=(ls cd mk rm prune merged help $(_wt_branches))
matches=(ls cd mk rm prune merged root help $(_wt_branches))
compadd -M 'l:|=*' -a matches
Comment thread
stilliard marked this conversation as resolved.
elif [ $CURRENT -gt 2 ]; then
case "${words[2]}" in
Expand Down Expand Up @@ -535,7 +546,7 @@ elif [ -n "$BASH_VERSION" ]; then
_wt_complete() {
local cur="${COMP_WORDS[COMP_CWORD]}"
if [ $COMP_CWORD -eq 1 ]; then
_wt_compreply "$cur" ls cd mk rm prune merged help $(_wt_branches)
_wt_compreply "$cur" ls cd mk rm prune merged root help $(_wt_branches)
else
case "${COMP_WORDS[1]}" in
rm|remove|cd|merged)
Expand Down