A fast, simple Git worktree helper written in Go. Inspired by haacked/dotfiles/tree-me.
- Configurable worktree strategies:
global,sibling-repo,parent-branches, and more - Clone into organized locations —
wt cloneacquires a repo underrepo_root(<host>/<owner>/<repo>/<branch>), ready to inspect - Simple commands for common worktree operations
- Interactive selection menus with fuzzy matching for checkout, cd, remove, pr, and mr commands
- GitHub PR support via
wt prcommand (usesghCLI) — checks out the PR's actual branch name - GitLab MR support via
wt mrcommand (usesglabCLI) — checks out the MR's actual branch name - Built-in file copy — declare
.envand friends in[files]or a committed.worktreeinclude; copied with a reflink on APFS/Btrfs/XFS, so evennode_modulescosts metadata rather than disk - Pre/post command hooks — run custom scripts on create/checkout/remove/clone (e.g. launch AI assistants, share build caches, assign dev server ports, init submodules)
- Stale worktree detection — find worktrees with deleted remote branches or inactive commits (
wt cleanup --stale) - Color-coded status output — green (clean), red (dirty), yellow (ahead/behind), bold cyan (current); respects
NO_COLOR=1and auto-strips colors when piped - CI/CD status integration —
wt status --cishows pipeline status (✓/✗/●) per branch viaghorglabCLI - Per-repo
.wt.tomlconfig — override global settings (strategy, hooks, etc.) on a per-repository basis git configsupport — keep personal settings in.git/configor~/.gitconfig, with no extra file to gitignore- Shell integration with auto-cd functionality
- Tab completion for Bash, Zsh, and Fish
brew install timvw/tap/wt # or: go install github.com/timvw/wt@latest
wt init # configure shell integrationSee docs/installation.md for all platforms (Scoop, WinGet, Linux packages, from source).
# Acquire the main repository, ready to inspect. Placed under repo_root as
# <repo_root>/<host>/<owner>/<repo>/<default-branch>, left on its default branch
# (that trailing segment makes the clone a normal worktree slot, so wt create
# later puts siblings next to it).
wt clone timvw/wt # owner/repo resolved via gh/glab
wt clone git@github.com:me/dotfiles.git # full URL used as-is
wt clone acme/api ~/src/api # explicit destinationTwo settings control placement: repo_root (default ~/dev/repos) and
repo_pattern. Grouping levels like "work" vs "personal" are yours to define —
put an env var in the pattern with a :- default so it works even when unset:
repo_pattern = "{.repoRoot}/{.env.WT_CATEGORY:-personal}/{.repo.Owner}/{.repo.Name}/{.branch}"WT_CATEGORY=work wt clone acme/api # ~/dev/repos/work/acme/api/main
wt clone timvw/wt # ~/dev/repos/personal/timvw/wt/main (default)To set the category for a whole tree of repos instead of per command, add a
[[context]] rule:
[[context]]
when_path = "~/dev/repos/work"
env = { WT_CATEGORY = "work" }Every wt command operating on a repo under that path then resolves work,
including wt create from a worktree in a different tree. The same rule can go
in ~/.gitconfig instead, if you would rather not keep a config file:
git config --global wt.context.work.whenpath "~/dev/repos/work"
git config --global --add wt.context.work.env "WT_CATEGORY=work"See Setting the category per directory.
# Checkout existing branch in new worktree
wt co feature-branch
wt co # interactive: fuzzy-search from available branches
# Create new branch in worktree (defaults to main/master as base)
wt create my-feature
wt create my-feature develop # specify base branch# Switch to a worktree that already exists (never creates one)
wt cd feature-branch
wt cd # interactive: fuzzy-search from existing worktrees
wt sw # alias for wt cdUnlike wt co, the wt cd list contains only branches that already have a worktree — including the main checkout — so it stays short in repositories with many branches.
# Checkout GitHub PR (requires gh CLI)
wt pr 123 # looks up branch for PR #123
wt pr https://github.com/org/repo/pull/123 # GitHub PR URL
wt pr # interactive: fuzzy-search from open PRs
# Checkout GitLab MR (requires glab CLI)
wt mr 123 # looks up branch for MR !123
wt mr https://gitlab.com/org/repo/-/merge_requests/123 # GitLab MR URL
wt mr # interactive: fuzzy-search from open MRsA new worktree has everything git tracks and nothing else — no .env, no
.envrc, no editor state. Declare what a usable checkout needs and wt puts it
there on create, checkout, pr and mr:
# ~/.config/wt/config.toml, or a repo's .wt.toml
[files]
copy = [".env", ".claude/settings.local.json"]
link = ["node_modules"]wt copy # re-run for the current worktree
wt copy feature-branch --dry-run # show what would happen, change nothing
wt copy feature-branch --force # overwrite files already there
wt create feature --no-copy # skip it just this onceOr commit a .worktreeinclude at the repo root — same gitignore syntax, one
pattern per line — so every contributor gets working worktrees without
configuring anything. Only untracked, git-ignored files are ever candidates; a
tracked file is already in the worktree and is never touched. See
Files.
wt ls # list all worktrees
wt rm old-branch # remove a worktree
wt rm # interactive: fuzzy-search worktree to removewt migrate # migrate worktrees to configured paths
wt migrate --force # force when target path exists
wt cleanup --stale # detect stale worktrees (deleted remotes, inactive commits)
wt cleanup --stale --stale-days 7 # custom inactivity threshold (default: 30 days)
wt prune # clean up stale worktree admin files
wt version # show version
wt examples # show practical examples
wt --help # show helpwt info # show active strategy, pattern, variables
wt config show # show effective config with sources
wt config init # create a default config file
wt config path # print the config file path
# Place a .wt.toml in a repo root to override global config for that repo
# Or keep it out of the working tree entirely, in git config:
git config --local wt.strategy sibling-repo # this repo only
git config --global wt.root ~/projects/worktreesA repo's .wt.toml is committed, so its [hooks] are supplied by the repository, not by you.
wt asks before running them and remembers your answer per file:
wt trust # approve this repository's .wt.toml hooks
wt trust --list # show every approval on this machine
wt untrust # revoke this repository's approvalThe approval is pinned to the file's contents, so an edit — or a git pull that adds a hook —
asks again. Non-interactive runs (scripts, CI, --format json) decline, unless you opt out with
WT_HOOKS_APPROVE_ALL=1. Set hooks_policy = "prompt-all" to confirm every hook, including
your own. See Hook trust.
On case-insensitive filesystems such as the default macOS APFS setup, mixed-case branch
prefixes can produce confusing worktree paths. For example, Feature/foo and
feature/bar both need a first-level directory that macOS treats as the same name.
Set separator = "-" to flatten branch paths (Feature/foo -> Feature-foo) and
avoid that class of collision. See Configuration.
wt status # color-coded overview of all worktrees
wt status --ci # include CI/CD pipeline status (requires gh or glab)Shows dirty/clean state, ahead/behind counts, and highlights the current worktree. With --ci, each branch shows ✓ (pass), ✗ (fail), or ● (pending) for its latest CI pipeline. Colors are automatically stripped when piping; set NO_COLOR=1 to disable.
When you run wt co, wt cd, wt rm, wt pr, or wt mr without arguments, you'll get an interactive selection menu. Typing filters the results with fuzzy matching, so you can quickly find the branch or worktree you're looking for.
wt co selects from every local and remote branch (creating a worktree when needed), while wt cd selects only from worktrees that already exist.
Most commands support machine-readable JSON output:
wt --format json version
wt --format json info
wt --format json config show
wt --format json list
wt --format json examplesIn json mode, shell integration does not auto-navigate. For commands that normally prompt interactively, pass explicit arguments when using --format json.
Install the Claude Code plugin to teach Claude how to work with wt-managed worktrees:
claude plugin marketplace add timvw/wt
claude plugin install wt@wt --scope localOnce installed, Claude understands wt commands, worktree strategies, and hooks — so you can ask it to create worktrees, set up hooks for copying .env files or running npm install / uv sync, and follow worktree-based workflows automatically.
See docs/examples.md for hooks that launch Claude Code in tmux per worktree.
| Topic | Description |
|---|---|
| Configuration | Config file, git config, strategies, patterns, separator, hooks, per-repo .wt.toml |
| Examples | Claude Code + tmux, multi-repo workflows, environment variables |
| Installation | All platforms, shell integration, building from source |
| Development | Building, testing, running from source |
| Claude Code Plugin | Plugin that teaches Claude Code how to work with wt |
The tool wraps Git's native worktree commands with a convenient interface and organized directory structure:
- Organized Structure: All worktrees for a repo are kept together
- Smart Defaults: Automatically detects repo name and default branch
- Prevents Duplicates: Checks if a worktree already exists before creating
- Auto-CD: With shell integration, automatically changes to the worktree directory
- Tab Completion: Makes it easy to work with existing branches
MIT
Based on tree-me by Phil Haack.





