Skip to content

Workflows & command reference

Workflows & command reference

The depth behind wt — every command and flag, the wt create --base start-point rules, the wt open launcher matrix, and the gotchas worth knowing. New here? Start with the install guide.

Run wt <command> --help for the same reference inline at your terminal.

Command reference

CommandSummary
wt create [branch]Create a worktree as a sibling of the main repo.
wt listList all worktrees with name, branch, and path.
wt open [name|path]Open a worktree (or any directory) in a detected app.
wt delete [names...]Delete one or more worktrees with optional branch cleanup.
wt initRun the per-worktree init script.
wt shell-initPrint the shell wrapper function for eval.
wt updateSelf-update the binary via Homebrew.

wt create [branch]

Creates a git worktree as a sibling of the main repo (<repo>.worktrees/<name>/). With no branch argument it makes an exploratory worktree on a new branch named after the random worktree name; with a branch argument it checks out that branch (existing) or creates it (new).

FlagDefaultDescription
--worktree-name <name>random adjective-nounSet the worktree directory name; skips the name prompt.
--worktree-init <true|false>trueRun the worktree init script after creation.
--worktree-open <prompt|default|skip|<app>>prompt (skip under --non-interactive)What to do after creation: show the app menu, open in the detected default, skip, or open in a named app (e.g. code, cursor).
--reusefalseIf a worktree with --worktree-name already exists, reuse it instead of erroring. Requires --worktree-name.
--non-interactivefalseNo prompts; fail or use defaults rather than prompting.
--base <ref>(none)Git start-point (branch / tag / SHA) for new branches. See the table below.

On success the worktree path is written as the last line of stdout (suppressed when the chosen app was “Open here”, because the shell wrapper consumed it via WT_CD_FILE).

wt list

Lists every worktree for the current repository. Discovery is O(1) — no per-worktree git invocations occur unless you ask for --status.

FlagDefaultDescription
--statusfalseAdd a Status column: * for dirty, ↑N for unpushed commits. Slower (forks git per worktree, parallelized). Mutually exclusive with --path.
--path <name>(none)Print only the absolute path for the named worktree. Mutually exclusive with --json and --status.
--jsonfalseEmit a JSON array of worktree records (name, branch, path, is_main, is_current; plus dirty/unpushed when --status is set). Mutually exclusive with --path.
--sort <recent|name|branch>(none)Order non-main worktrees by most-recently-modified, name, or branch.
--non-interactivefalseUse the stable (name) default ordering, suitable for scripts.

wt open [name|path]

The canonical directory launcher in the toolkit (other tools, like hop, delegate to it). What it does depends on where you run it and what you pass — see the launcher matrix.

FlagDefaultDescription
--app <name|default>(none)Open directly in the named app, skipping the menu. default selects the auto-detected default. Incompatible with the main-repo selection menu.

wt delete [worktree-names...]

Deletes one or more worktrees with optional branch cleanup. Resolution priority: --delete-all → positional names → current worktree → interactive selection menu.

FlagDefaultDescription
--delete-branch <true|false|auto>autoDelete the associated local branch. auto deletes only when the branch name matches the worktree name.
--delete-remote <true|false>trueDelete the remote-tracking branch when the local branch is deleted.
--delete-allfalseDelete every worktree (skips the selection logic).
-s, --stashfalseStash uncommitted changes in the worktree before deleting.
--stale[=Nd]7d when bareSelect idle worktrees (filesystem mtime older than the threshold) for deletion. Bare --stale uses the 7-day default; --stale=30d overrides. The = is required.
--non-interactivefalseNo prompts; use defaults.

wt init

Runs the per-worktree init script for the current worktree. The script is resolved from WORKTREE_INIT_SCRIPT (if set and non-empty), otherwise it defaults to fab sync. A value containing a space is treated as a command invocation; a value without spaces is treated as a script path relative to the main repo root. The script runs with its working directory set to the current worktree’s top level. No flags, no positional args.

If the init command or file can’t be located, wt init prints a guidance warning and exits 0 (a graceful skip) — so a freshly cloned repo without an init script just no-ops. If the script is found but exits non-zero, wt surfaces a typed init-failure exit code so wrappers can offer a retry.

wt shell-init

Prints a bash/zsh wrapper function to stdout for eval in your shell profile. See the install guide for setup. No flags, no positional args; always exits 0.

wt update

Self-updates the wt binary via Homebrew. Runs a brew update, queries the tap formula (sahil87/tap/wt) for the latest stable version, and runs brew upgrade only when a newer version is available.

FlagDefaultDescription
--skip-brew-updatefalseSkip the internal brew update tap-metadata refresh (the version check and upgrade still run).

If wt was installed via just local-install (in ~/.local/bin) rather than Homebrew, wt update reports that and tells you to reinstall with brew install sahil87/tap/wt instead of attempting a self-update.

wt create --base — branch start-point

--base <ref> controls the start-point when wt creates a new branch (it maps to git worktree add -b <branch> <path> <start-point>). Behavior depends on whether the branch already exists:

Scenario--baseBehavior
New branch (doesn’t exist locally or remotely)providedBranch created from the --base ref.
New branchomittedBranch created from HEAD (default).
Existing local branchprovidedWarning: --base ignored: branch already exists locally.
Existing remote branchprovidedWarning: --base ignored: fetching existing remote branch.
Exploratory (no branch arg)providedExploratory branch created from the --base ref.
ExploratoryomittedBranch created from the current HEAD (default).
With --reuse (worktree exists)provided--reuse takes precedence; --base has no effect.
Invalid refprovidedError exit; no worktree or branch created.

The ref is validated with git rev-parse --verify before worktree creation, so an invalid ref produces a clear error rather than a partial failure.

wt open — context-aware launcher

wt open is the one command worth knowing in detail. What it does depends on where you run it from and what you pass it:

Where you areWhat you typeWhat happens
Inside a worktreewt openOpens the current worktree in your editor / terminal / file manager.
In the main repowt openShows a worktree-selection menu (most recently modified is highlighted).
In a non-git directorywt openOpens the current directory (equivalent to wt open .).
Anywherewt open lively-otterResolves the name against this repo’s worktrees and opens it. (Requires a git repo.)
Anywherewt open /tmp/notesOpens that directory literally — git context doesn’t matter.
Anywherewt open --app cursorSkips the menu and opens in the named app.

Path-arg precedence: when you supply an argument, wt tries it as a literal directory path first; only if that’s not an existing directory (and the cwd is inside a git repo) does it fall back to resolving the argument as a worktree name.

The menu lists the apps wt detected on your machine (editors, terminals, file managers) plus an “Open here” option that cds your current shell into the target — that one needs the shell wrapper (see Gotchas).

Running wt open from the main repo, with two worktrees on disk:

$ wt open
Select worktree to open:
  1) lively-otter (feature/spinner) (default)
  2) bold-fox    (fix/race-condition)
  0) Cancel

Choice [1]: 1
Open in:
  1) Open here
  2) VSCode (default)
  3) Cursor
  4) Ghostty
  5) Terminal.app
  6) Finder
  7) Copy path
  0) Cancel

Choice [2]:

Pick 1 to cd your shell into the worktree, 26 to launch it in a detected app, or 7 to copy the absolute path to your clipboard.

Worktree layout

Worktrees live as siblings of the main repo, grouped under one per-repo directory:

<parent>/
├── <repo>/                  # main repo
└── <repo>.worktrees/        # all linked worktrees for this repo
    ├── swift-fox/
    ├── jolly-otter/
    └── crimson-heron/

Names are random adjective-noun pairs (swift-fox, jolly-otter), with the generator retrying up to 10 times to avoid collisions; pass --worktree-name to choose your own. The branch checked out in a worktree is independent of the worktree directory name — for an exploratory worktree the two happen to match, but for a worktree created on an existing branch they differ freely.

Gotchas

  • wt open can’t cd without the shell wrapper. A child process can’t change its parent shell’s directory — that’s a Unix constraint, not a wt bug. eval "$(wt shell-init)" installs a shell function that wraps the binary so the “Open here” menu option actually works. See the install guide.
  • --base is ignored when the branch already exists (locally or on the remote) — wt checks out the existing branch instead and prints a warning. --reuse also takes precedence over --base.
  • Worktrees survive cd into deleted directories. If you delete a worktree from outside (rm -rf), run git worktree prune in the main repo to clean up git’s bookkeeping.
  • Name resolution needs a git repo, path args don’t. wt open <name> walks the worktree list and so requires a git repo; wt open <path> works from any directory because it’s a literal path.
  • wt init no-ops gracefully when no script is found. A fresh clone without an init script (and without fab-kit installed) silently does nothing on wt init — that’s intentional for the “I just want to use the worktree” path.

See also

  • Install guide — Homebrew, manual install, and the shell wrapper.
  • Releases — download a packaged binary directly.