Skip to content

Repository files navigation

wt — Git Worktree Provisioner

wt is an ergonomic CLI for working with git worktrees. It creates, switches between, and tears down worktrees with zero config for the basics — plus optional per-project automation for setup commands, file symlinks, and background services.

Built with Bun.

Features

  • Conventions over configurationwt my-feature just works; no config required.
  • Smart branch detection — checks out a local or remote branch, or creates a new one.
  • cd into your worktree — the shell integration drops you straight into the new worktree on create/switch.
  • Automatic setup — run install/migration commands in each new worktree (setup-worktree).
  • Teardown hooks — run cleanup commands before a worktree is removed (teardown-worktree).
  • File symlinking — share node_modules, .env, data dirs, etc. from the main worktree (opt-in).
  • Service orchestration — start/stop background services per worktree, ensuring only the active worktree's services run (wt run).
  • Interactive cleanup — multi-select stale worktrees to remove (wt clean).
  • Scriptable--json output plus wt path / wt exists make it easy to build other tooling on top.

Requirements

  • Bun
  • Git 2.5+ (worktree support)
  • zsh (for the shell integration and completion installer)

Install

git clone https://github.com/DXTimer/wt.git
cd wt
bun install
bun wt install      # configures PATH, shell wrapper, and completion
source ~/.zshrc

wt install is idempotent — safe on a fresh or already-configured machine. It:

  • runs bun install
  • adds wt to your PATH
  • installs the shell wrapper so wt create/wt switch change your current directory into the worktree
  • enables zsh tab completion

It manages a single marked block in ~/.zshrc (honoring $ZDOTDIR), so re-running never duplicates setup.

Useful flags:

bun wt install --print          # print the shell block without writing anything
bun wt install --skip-install   # configure the shell but skip `bun install`

Prefer to wire it up by hand? See Shell integration below.

Quick start

wt feature/login          # create + cd into a worktree for feature/login
wt ls                     # list all worktrees
wt sw -                   # switch back to the previous worktree
wt rm feature/login       # remove it

Commands

Command Description
wt <branch> [path] Create a worktree (default command). Detects a local/remote branch or creates a new one.
wt switch | sw [name|-] Switch to a worktree (interactive, by name, or - for the previous one).
wt list | ls List all worktrees with branch, commit, and path.
wt remove | rm | delete <name> Remove a worktree by branch, path, or directory name. Runs teardown-worktree first.
wt clean | cleanup Interactive multi-select removal of worktrees.
wt setup [name] Re-run setup (symlinks + commands) on an existing worktree.
wt run <worktree> [services...] Start the worktree's services/modifiers, stopping conflicting ones running elsewhere.
wt logs [service|all] Stream service logs.
wt path --branch <name> Print the filesystem path of a branch's worktree.
wt exists --branch <name> Exit 0 if a worktree exists for the branch.
wt install | init Set up / refresh the zsh integration (idempotent).

Common flags: --force and --delete-branch (remove); --skip-links, --skip-setup, --verbose/-v (create/setup); and the global --json and --project <path>.

Creating worktrees

wt feature/authentication           # existing remote branch
wt feature/new-feature              # new branch
wt hotfix/critical-bug ~/wt/urgent  # custom path

By default, worktrees are created at ../worktrees/<branch-name> relative to your git root, with the branch name sanitized (feature/loginfeature-login). For a repo at /Users/you/projects/myapp, wt feature/login creates /Users/you/projects/worktrees/feature-login.

Removing worktrees

wt rm feature/authentication   # by branch name
wt rm feature-authentication   # by directory name
wt rm --force old-branch       # even with uncommitted changes
wt rm --delete-branch stale    # also delete the branch
wt clean                       # interactive multi-select

Configuration

Create .wt/worktrees.json in your project root (or any ancestor directory up to ~). All keys are optional — see .wt/worktrees.json.example for a complete example.

{
  "setup-worktree": [
    "bun install",
    "cp $WT_MAIN/.env .env"
  ],
  "teardown-worktree": [
    "docker compose down || true"
  ],
  "symlinks": {
    "patterns": ["node_modules", ".env*", "*.sqlite", ".data/**"],
    "exclude": [".env.test", ".env.example"]
  },
  "services": {
    "backend": {
      "start": "bun run dev:backend > .backend.log 2>&1 &",
      "check": "pgrep -f 'bun run dev:backend'",
      "stop": "pkill -f 'bun run dev:backend'",
      "logs": "tail -f .backend.log"
    }
  },
  "modifiers": {
    "seed": "bun run db:seed"
  }
}
Key Purpose
setup-worktree Commands run, in order, in each new worktree after creation.
teardown-worktree Best-effort commands run in a worktree before it is removed.
symlinks Glob patterns (and optional exclude) of files to symlink from the main worktree. Opt-in.
services Named start/stop/check/logs commands managed by wt run. wt run ensures a service runs only for the active worktree.
modifiers Named one-off commands invoked via wt run <worktree> <modifier>.

A command ending in || true (or || :) is treated as soft: a failure logs a warning instead of aborting setup.

Environment variables

Setup, teardown, and modifier commands receive:

Variable Value
$WT_MAIN Path to the main worktree (original checkout).
$WT_PATH Path to the worktree the command is running in.
$WT_GIT_ROOT Git root directory.
$WT_BRANCH Branch name (available in teardown and wt run).

Legacy: if no .wt/worktrees.json is found, wt falls back to .cursor/worktrees.json for backward compatibility.

Shell integration

wt install does this for you. To wire it up by hand, add the following to ~/.zshrc (replace the paths):

export PATH="/path/to/wt/bin:$PATH"

# cd into the worktree after create/switch
wt() {
  command wt "$@"
  if [[ -f /tmp/wt_switch_target ]]; then
    cd "$(cat /tmp/wt_switch_target)"
    rm /tmp/wt_switch_target
  fi
}

# Completion (zsh)
fpath=(/path/to/wt/completion $fpath)
autoload -Uz compinit && compinit

Scripting & JSON output

wt is built to be composed with other tools:

# Get the path of a worktree (prints just the path)
dir=$(wt path --branch feature/login)

# Or as JSON: { "path": "...", "branch": "...", "exists": true }
dir=$(wt path --branch feature/login --json | jq -r .path)

# Guard on existence (exits non-zero if missing)
wt exists --branch feature/login && echo "already provisioned"

--json makes commands emit machine-readable output on stdout while informational logs go to stderr — which is what programmatic consumers (including Claude Code worktree hooks) rely on. --project <path> runs against a repo other than the current directory.

Configuring with an AI agent

docs/ai_config_prompt.md is a ready-made prompt for having an AI assistant generate a .wt/worktrees.json tailored to your project.

License

MIT © Ivan Bakalov


Built and maintained by Ivan Bakalov.

About

Ergonomic git worktree provisioner — automatic setup, symlinks, and per-worktree service orchestration.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages