wt is a fast, deterministic CLI for creating and managing git worktrees without interactive prompts. Stop juggling branches in a single working directory - work on multiple features simultaneously with isolated, organized worktrees.
# Create a worktree for a new feature
wt new my-feature
# See what you're working on
wt status
# Keep everything in sync
wt pull-main --stash
# Clean up merged work
wt prune-merged --yes- Why wt?
- Quick Start
- Tutorial: Your First Worktree
- How-To Guides
- Configuration
- Hooks System
- Advanced Topics
- Troubleshooting
Git worktrees let you check out multiple branches simultaneously in separate directories. They're perfect for:
- Working on multiple features without stashing or committing incomplete work
- Running tests on one branch while developing on another
- Reviewing PRs in isolation without disrupting your current work
- Keeping long-running branches separate from daily work
But vanilla git worktrees are tedious: paths are manual, cleanup is forgotten, and there's no workflow automation.
wt fixes this: deterministic paths via templates, automatic cleanup, post-create hooks, and zero prompts for scripting.
Important
Requires Python ≥3.11 (for native TOML support via tomllib)
Install uv, then run:
uv tool install wt-cli
# Verify installation
wt doctor# Create a worktree for a new feature branch
wt new my-feature
# -> /Users/you/repos/myproject-worktrees/my-feature
# List all worktrees
wt list
# See status with tracking info
wt status --rich
# Jump to a worktree
cd $(wt where my-feature)
# Remove a worktree when done
wt rm my-feature --yes --delete-branchLet's create a worktree for a new feature, make some changes, and clean up.
cd ~/repos/myproject
wt new login-redesignThis creates a new branch login-redesign from origin/main and checks it out in a separate directory adjacent to your repo:
~/repos/myproject-worktrees/login-redesign
Important
By default, wt new branches from origin/main, not your current branch. This is different from git checkout -b. To branch from a different base, use wt new my-feature --from origin/develop or configure a different default in [update] base.
cd $(wt where login-redesign)
# Make your changes
git add .
git commit -m "Redesign login form"
git push -u origin login-redesignYour main worktree is untouched - you can keep working there simultaneously.
# From anywhere in your repo
wt pull-main --stashThis fetches updates and rebases (or merges) all your worktrees with origin/main, stashing dirty changes automatically.
After your PR is merged:
wt prune-merged --yes --delete-branchAutomatically removes worktrees for merged branches and optionally deletes the local branches too.
Add your username to all new branches automatically:
~/.config/wt/config.toml:
[branches]
auto_prefix = "alice/"Now wt new feature creates branch alice/feature.
Use template variables to organize worktrees:
~/repos/myproject/.wt/config.toml:
[paths]
worktree_root = "/Users/alice/work"
worktree_path_template = "$WT_ROOT/$REPO_NAME/$BRANCH_NAME"Variables available:
$REPO_ROOT- Absolute path to main repo$REPO_NAME- Repository directory name$WT_ROOT- Resolved worktree root$BRANCH_NAME- Branch name (with slashes for nesting)$SOURCE_BRANCH- Branch this worktree was created from$DATE_ISO/$TIME_ISO- Timestamps
Tip
Branch names containing slashes (e.g., feature/login) automatically create nested directories. Useful for organizing worktrees by category.
Hooks automatically run scripts after creating a new worktree. Use them to install dependencies, open editors, or initialize databases.
Quick start:
# Create global hooks directory with example template
wt hooks init --template
# Edit the template to customize
# ~/.config/wt/hooks/post_create.d/00-example.sh
# Or create local hooks for a specific repo
wt hooks init --local --templateTip
See examples/hooks/ for ready-to-use hook examples including npm install, Python venv setup, VS Code integration, Docker Compose, and more. Copy them to your hooks directory to get started quickly.
Example: Install dependencies automatically
Create a hook file at ~/repos/myproject/.wt/hooks/post_create.d/01-install.sh:
#!/bin/bash
set -e
echo "Installing dependencies in $WT_WORKTREE_PATH..."
npm installMake it executable:
chmod +x ~/repos/myproject/.wt/hooks/post_create.d/01-install.shOr use wt hooks init --local --template to create an example hook that's already executable.
Check your hooks:
# List all hooks and their status
wt hooks listHook environment variables:
WT_REPO_ROOT,WT_REPO_NAMEWT_BRANCH_NAME,WT_SOURCE_BRANCHWT_WORKTREE_PATHWT_DATE_ISO,WT_TIME_ISO- All template variables available as
WT_*
# Merge instead of rebase
wt pull-main --strategy merge
# Fast-forward only (fails on divergence)
wt pull-main --strategy ff-onlySet defaults in config:
[update]
base = "origin/develop" # Use develop instead of main
strategy = "merge" # Default to merge
auto_stash = true # Always stash automaticallyPrevent accidental deletion during batch operations:
[prune]
protected = ["main", "develop", "staging"]
delete_branch_with_worktree = falseTip
Protected branches only affect wt prune-merged (batch cleanup). They do not prevent wt rm <branch> (explicit removal), since explicitly naming a branch indicates intent.
# Print path (useful for scripting)
wt where my-feature
# Jump to worktree
cd $(wt where my-feature)
# Open in editor
code $(wt where my-feature)If you removed a worktree but kept the branch, you can recreate it:
# Previously: wt rm my-feature (without --delete-branch)
# Branch still exists, but no worktree
# Recreate the worktree for the existing branch
wt new my-feature
# This checks out the existing branch at a new worktree locationWarning
You cannot create multiple worktrees for the same branch. Git prevents the same branch from being checked out in multiple locations simultaneously.
Use the example hook to automatically create VS Code settings that make each worktree window unique:
# Copy the VS Code settings hook to your hooks directory
cp examples/hooks/09-vscode-settings.py ~/.config/wt/hooks/post_create.d/
# Or for a specific repo
cp examples/hooks/09-vscode-settings.py .wt/hooks/post_create.d/This hook creates .vscode/settings.json in new worktrees with:
- Colored window borders - Each branch gets a unique color (generated from branch name hash)
- Custom window title - Shows
{repo_name} | {branch_name}instead of just the path
This makes it easy to visually distinguish between multiple VS Code windows when working across worktrees.
Note
Settings are only created if .vscode/settings.json doesn't already exist, so existing customizations are preserved.
Configuration uses TOML with precedence: CLI args > local > global > defaults
Global: ~/.config/wt/config.toml (all repos)
Local: <repo>/.wt/config.toml (specific repo)
[paths]
worktree_root = "$REPO_ROOT/../$REPO_NAME-worktrees"
worktree_path_template = "$WT_ROOT/$BRANCH_NAME"
[branches]
auto_prefix = "alice/"
[hooks]
post_create_dir = "post_create.d"
continue_on_error = false
timeout_seconds = 300
[update]
base = "origin/main"
strategy = "rebase" # or "merge", "ff-only"
auto_stash = false
[prune]
protected = ["main", "develop"]
delete_branch_with_worktree = false
[ui]
rich = false
json_indent = 2- Worktree location: Sibling directory to your repo
- Repo at
/Users/alice/repos/myproject - Worktrees at
/Users/alice/repos/myproject-worktrees/
- Repo at
- Base branch:
origin/main - Update strategy:
rebase - Protected branches:
["main"]
Hooks automatically run scripts after creating new worktrees, enabling workflow automation.
Initialize hooks with a template:
# Create global hooks directory with example template
wt hooks init --template
# Create local hooks directory (repo-specific)
wt hooks init --local --template
# List all configured hooks
wt hooks listThe --template flag creates an example hook (00-example.sh) that documents all available environment variables and includes common examples.
Hooks run in two phases:
- Local hooks first: All executable files from
<repo>/.wt/hooks/post_create.d/(sorted alphabetically) - Global hooks second: All executable files from
~/.config/wt/hooks/post_create.d/(sorted alphabetically)
This gives repo-specific hooks priority to run before global hooks.
Supported:
- Shell scripts:
*.sh - Python scripts:
*.py(run withuv run, supports inline script metadata) - Any executable
Tip
Use wt hooks list to check which hooks are configured and whether they're executable. Non-executable hooks are detected and you'll get instructions to fix them with chmod +x.
Note
All template variables are automatically injected as WT_* environment variables into your hooks.
#!/bin/bash
echo "Created worktree for $WT_BRANCH_NAME at $WT_WORKTREE_PATH"
echo "Repo: $WT_REPO_NAME ($WT_REPO_ROOT)"See examples/hooks/ for a complete collection of ready-to-use hooks. Here are a few quick examples:
Install dependencies:
#!/bin/bash
# .wt/hooks/post_create.d/01-npm-install.sh
set -e
echo "Installing npm dependencies..."
npm install --quiet
echo "✓ Dependencies installed"Open worktree in editor:
#!/bin/bash
# ~/.config/wt/hooks/post_create.d/03-open-vscode.sh
code .Python virtual environment:
#!/bin/bash
# .wt/hooks/post_create.d/02-python-venv.sh
set -e
if [ -f "requirements.txt" ]; then
echo "Creating Python virtual environment..."
python -m venv .venv
.venv/bin/pip install -r requirements.txt --quiet
echo "✓ Virtual environment ready"
fiCopy environment files from main repo:
#!/bin/bash
# .wt/hooks/post_create.d/05-setup-env.sh
set -e
if [ -f "$WT_REPO_ROOT/.env.local" ]; then
cp "$WT_REPO_ROOT/.env.local" .env.local
echo "✓ Environment file copied"
fiTip
Copy hooks from examples/hooks/ to your hooks directory and make them executable with chmod +x. See the examples README for installation instructions and more examples.
All commands support JSON output and use exit codes:
# Get all worktrees as JSON
wt list --json | jq -r '.[] | select(.dirty) | .path'
# Find worktrees behind main
wt status --json | jq -r '.[] | select(.behind_main > 0) | .branch'
# Batch operations
for branch in $(wt list --json | jq -r '.[].branch'); do
cd $(wt where $branch)
npm test
doneImportant
wt uses a repo-scoped advisory lock (.git/wt.lock) to prevent concurrent modifications. Operations are serialized per-repo but can run concurrently across different repos.
Fully supported. Uses PID-based locking on Windows instead of fcntl.
- Single
git fetchper operation (not per worktree) - Serial execution with minimal subprocess overhead
- Stdlib-only, no external dependencies
Caution
Manually deleting worktree directories (with rm -rf or file explorer) leaves stale git entries. Always use wt rm instead.
If you already manually deleted a worktree directory:
wt gcIncrease timeout in config:
[hooks]
timeout_seconds = 600Check your auto_prefix config:
wt doctorEnsure paths don't contain special shell characters. Quote template variables if using spaces.
MIT
