wt
wt
A small Crystal CLI for managing git worktrees.
Install
Requires Crystal (brew install crystal).
make install
Add to your .zshrc:
eval "$(command wt init zsh)"
Reload your shell (exec zsh) and you're set. make uninstall removes the binary.
Usage
Switch to a worktree (exact or unique-prefix match, tab-completes):
wt [name]
wt cd <name>
Create a worktree, optionally from a base ref:
wt new <branch> [base]
When the branch exists, wt new checks it out into a new worktree. When the branch is new, it creates it from [base], or from the current HEAD if no base is provided. Either way, it switches into the worktree when it finishes.
Remove a worktree (branch preserved):
wt rm [name]
List worktrees:
wt ls
Other commands:
wt help
wt --version
Resolution
When you pass a name, wt resolves it directly: exact match first, then unique prefix, then error with candidates.
When you omit the name, wt lists the available worktrees.
Tab completion
Tab completion is set up automatically by wt init zsh. It completes:
wt cd <tab>/wt rm <tab>: worktree nameswt new <tab>: branch nameswt new <branch> <tab>: branch/ref names for the base
Configuration
Per-repo .wt.yml (committed, shared with the team) with an optional .wt.local.yml override (gitignored, personal). Global defaults in ~/.config/wt/config.yml. Merge order: global, repo, local.
copy:
- .env
- .env.local
- config/master.key
after_create:
- bundle install
- yarn install
copy
Files to copy from the main worktree into the new one. These are typically gitignored, so they don't come across with the checkout. Missing sources are skipped with a warning.
after_create
Commands run in the new worktree's directory, in order, streaming output. Stops on first non-zero exit. The worktree is already created, so it stays in place for you to fix manually.
--no-hooks
Skip all copy and after_create steps on wt new.
Trust model
.wt.yml can be committed to a repo, and after_create runs arbitrary shell commands. This is the same trust model as Makefiles and npm scripts: review .wt.yml before running wt new in an untrusted repo, or pass --no-hooks.
Shell integration
The cd problem
A compiled binary can't cd your shell (it's a child process). So wt is a binary + thin shim, like zoxide or rbenv:
- The binary holds all logic (resolve paths, create/remove worktrees, format output).
- A tiny shell function calls the binary and
evals its stdout for navigation commands.
Both are named wt. The function shadows the binary for interactive use and delegates with command wt (which bypasses functions and runs the executable on PATH).
Stdout protocol
The binary emits two kinds of output on stdout:
- Directives the shim
evals (e.g.cd <path>) - Plain text the shim prints as-is (ls, help, messages)
Errors and human messages go to stderr so they never get evald and hook output (bundle install, etc.) streams live.
Worktree conventions
- Worktrees live in
<repo>/.worktrees/<branch>. /in branch names becomes-for the directory (feature/foobecomes.worktrees/feature-foo)..worktrees/is added to.git/info/exclude(local-only, never the committed.gitignore).
Development
make build
make test
make test runs crystal spec.
wt
- 0
- 0
- 0
- 0
- 0
- about 2 hours ago
- June 22, 2026
Mon, 22 Jun 2026 16:48:21 GMT