Git worktree manager powered by fzf.
Quickly list, switch to, create, or remove git worktrees with fuzzy search.
brew install RodrigoEspinosa/tap/wtgit clone https://github.com/RodrigoEspinosa/wt.git
cd wt
make installThis installs wt to /usr/local/bin by default. Override with PREFIX:
make install PREFIX=$HOME/.localbrew uninstall wt # Homebrew
make uninstall # from sourcegit2.5 or newer (for worktree support)- fzf
- Install
wt(see above). - Add shell integration to your rc file:
# zsh
eval "$(wt init zsh)"
# bash
eval "$(wt init bash)"
# fish
wt init fish | source- Run
wtinside any git repository.
wt # Interactive fuzzy picker
wt my-feature # Switch to branch worktree (creates if needed)
wt my-feature main # Create the branch from main if it doesn't exist
wt pr 123 # Check out GitHub PR #123 in a worktree
wt clean # Pick and remove merged/stale worktrees
wt clean --prune --yes # Prune remotes, then remove every candidate non-interactively
wt -d my-feature # Remove a worktree
wt -l # List worktrees (marks current `*`, dirty `!`, ahead/behind)Inside the interactive picker: enter switches to the highlighted worktree, ctrl-n creates a worktree from whatever you've typed, and ctrl-d / del removes the highlighted one.
| Command | Description |
|---|---|
wt |
Launch fzf to fuzzy-pick a worktree |
wt <branch> [<start-point>] |
Switch to the worktree for <branch>, creating it if it doesn't exist. A new branch starts at <start-point> (commit, branch, or tag) if given |
wt pr <number> |
Fetch a GitHub pull request and check it out in a worktree |
wt clean [--prune] [--yes] |
Multi-select and remove worktrees whose branch is merged or whose upstream is gone. --prune fetches/prunes remotes first; --yes removes all candidates without prompting |
wt -d <branch> |
Remove the worktree for <branch>, deleting the local branch too if it is fully merged |
wt -l |
List all worktrees, marking the current one (*), uncommitted changes (!), and ahead/behind upstream |
wt init <shell> |
Print shell integration for bash, zsh, or fish |
wt -h |
Show help |
wt -v |
Show version |
A fresh worktree is a clean checkout — it's missing the untracked files that make a repo usable (.env, node_modules, build caches). Drop a .wtconfig at the repo root and wt will prepare each newly created worktree for you:
# .wtconfig
copy = .env # copy a file/dir from the primary worktree
copy = .env.local
link = node_modules # symlink instead of copy (good for big dirs)
postCreate = pnpm install # shell command run inside the new worktreecopy/link/postCreatemay each appear multiple times; they run in that order.baseDir = <path>sets where this repo's worktrees live (relative paths resolve against the repo root,~expands to your home).WT_BASE_DIRoverrides it.copyandlinksources are resolved against the primary worktree; missing sources are skipped with a notice.postCreateruns with the new worktree as the working directory and can read$WT_BRANCH,$WT_PATH, and$WT_SOURCE.- All hook output goes to stderr, so the shell wrapper still
cds you in cleanly. SetWT_NO_HOOKS=1to skip hooks for one run.
Because hooks leave untracked files behind, wt -d and wt clean force past untracked files when removing a worktree but still refuse to delete one with uncommitted changes to tracked files.
wt pr <number> fetches refs/pull/<number>/head from origin (or your first remote) into a local branch and checks it out in a worktree — perfect for reviewing a PR without disturbing your current work. If gh is installed, the worktree is named after the PR's head branch; otherwise it falls back to pr-<number>.
wt clean finds worktrees whose branch is fully merged into the default branch or whose upstream has been deleted ([gone]), and offers them in an fzf multi-select list (Tab to mark, Enter to remove). Without fzf it prints the candidates so you can remove them with wt -d.
--prunerunsgit fetch --all --prunefirst, so branches whose upstream was deleted on the remote are detected as[gone].--yes(alias--all) skips the picker and removes every candidate — handy for scripts and CI.
wt prints the selected worktree path to stdout. A subprocess can't change the parent shell's working directory, so wt init <shell> outputs a thin wrapper function that captures the path and cds into it. It also provides tab completions for branches, worktrees, and options.
| Key | Action |
|---|---|
Enter |
Select worktree (prints path) |
Ctrl-N |
Create a worktree from the typed query |
Ctrl-D / Del |
Delete the highlighted worktree |
The preview pane on the right shows the working-tree status and the last 10 commits for the highlighted worktree.
| Variable | Description | Default |
|---|---|---|
WT_BASE_DIR |
Parent directory for new worktrees | <repo>/_worktrees |
WT_NO_HOOKS |
When set, skip .wtconfig copy/link/postCreate hooks |
(unset) |
When WT_BASE_DIR is not set, wt uses the baseDir key from .wtconfig if present, otherwise a _worktrees/ directory at the root of the repository. Branch names with slashes (e.g. rec/my-branch) are flattened to a single directory (_worktrees/rec-my-branch); the branch itself keeps its original name. If two branches would flatten to the same directory (e.g. rec/foo and rec-foo), wt refuses to create the second rather than dropping you in the wrong worktree.
A man page is included at doc/wt.1. make install installs it alongside the
binary. To install just the man page:
# With make
make install-man
# Or manually
cp doc/wt.1 /usr/local/share/man/man1/After installing, view it with man wt.
