Git worktree manager with GitHub integration. Shows CI status, PR review state, and cleans up merged worktrees automatically.
- Create worktrees from a bare repo with one command
- List worktrees with last commit, PR number, CI pass/fail, and review status
- Prune worktrees whose PRs have been merged
- Multi-repo support via simple config files
- VS Code workspace sync (optional) — auto-adds/removes worktrees
Note: VS Code uses JSONC (JSON with comments/trailing commas) for workspace files. When
wtmodifies the file, it converts it to strict JSON — any comments in the file will be lost. - Shared files — symlink common untracked files into new worktrees (changes sync across all worktrees)
- Zsh integration — cd wrapper and tab completion
brew install francofrizzo/tap/wtgit clone https://github.com/francofrizzo/wt.git
ln -s "$PWD/wt/bin/wt" /usr/local/bin/wt- macOS with zsh (target platform)
- Bash 3.2+ (ships with macOS)
- git
- gh — GitHub CLI (for PR/CI status)
- jq — JSON processor
- perl — JSONC processing (ships with macOS)
The quickest way to get started — clone a GitHub repo:
wt init https://github.com/owner/myprojectThis clones it as a bare repo, detects the GitHub slug and default branch, and writes the config. You're ready to create worktrees immediately.
# Already inside a worktree or bare repo:
wt init
# Have an existing bare repo:
wt init myproject --bare ~/code/myproject.gitAll three modes accept these optional flags:
| Option | Description | Default |
|---|---|---|
--worktrees |
Directory for worktrees | <bare-parent>/<name>-worktrees |
--repo |
GitHub owner/repo slug |
auto-detected from remote |
--workspace |
VS Code .code-workspace file |
none |
--shared |
Directory symlinked into new worktrees | none |
--default-branch |
Default branch name | auto-detected from remote HEAD |
Each repo is a sourceable shell file at ~/.config/wt/repos/<name>.conf:
BARE="/Users/you/code/myproject.git"
WORKTREES="/Users/you/code/myproject-worktrees"
REPO="owner/myproject"
DEFAULT_BRANCH="main"wt my-feature # new branch off origin/main
wt my-feature origin/dev # new branch off origin/dev
wt my-feature HEAD # new branch off the current branch
wt add my-feature # explicit add subcommand
wt add my-feature --no-symlink # copy shared files instead of symlinkingIf the branch exists locally or on the remote, it checks it out. Otherwise, it creates a new branch from the base ref.
The worktree path is printed to stdout, so you can use it in scripts:
cd $(wt my-feature)wt listOutput shows each worktree with:
- Branch name and directory
- Last commit (relative time + message)
- PR number with CI status (pass/fail/running) and review state (approved/changes/pending)
- Merged PRs shown dimmed
wt cd my-featurewt fork new-branch # fork current branch into new-branch
wt fork new-branch --keep # fork and keep changes in both worktrees
wt fork new-branch --no-symlink # copy shared files instead of symlinkingCreates a new worktree branching from the current one. If you have uncommitted changes (staged, unstaged, or untracked), they are moved to the new worktree automatically. Use --keep to preserve the changes in the original worktree as well.
wt rm my-feature
wt rm -f my-feature # force remove (even if dirty)Also cleans up the local branch if it has been fully merged.
wt prune # interactive — prompts before removing
wt prune --dry-run # preview what would be removedFinds all worktrees whose PRs have been merged on GitHub (or have no unique commits vs the default branch) and removes them.
wt reposwt --repo myproject listBy default, wt auto-detects the repo based on your current directory. The --repo flag is only needed when you're outside any configured worktree path.
Add to your ~/.zshrc:
source "$(brew --prefix)/share/wt/wt.zsh"This gives you:
- Auto-cd:
wt my-featurecreates the worktree andcds into it - Tab completion: subcommands, branch names, worktree names,
--reponames
wt operates on bare git repositories. Instead of cloning a repo normally, you clone it bare and create worktrees for each branch you work on. This lets you have multiple branches checked out simultaneously without stashing or switching.
Why bare repos? A normal clone has a single working tree tied to .git. Worktrees created from it share that .git directory, which can cause issues with IDE indexing, build caches, and lock files. A bare repo has no working tree of its own — every branch gets its own independent directory, cleanly isolated from each other.
~/code/
myproject.git/ # bare repo (no working tree)
myproject-worktrees/
main/ # worktree for main
feature-auth/ # worktree for feature-auth
fix-login-bug/ # worktree for fix-login-bug
Run the release script:
./release.sh 0.2.0This tags the release, computes the tarball SHA, updates the Homebrew formula, and pushes everything. Users then run brew upgrade wt.