wt switch
Switch to a worktree; create if needed.
Worktrees are addressed by branch name; paths are computed from a configurable template. Unlike git switch, this navigates between worktrees rather than changing branches in place.
Examples
Section titled “Examples”wt switch feature-auth # Switch to worktreewt switch - # Previous worktree (like cd -)wt switch --create new-feature # Create new branch and worktreewt switch --create hotfix --base productionwt switch pr:123 # Switch to PR #123's branchwt switch https://github.com/owner/repo/pull/123 # ...or paste the PR's URLCreating a branch
Section titled “Creating a branch”The --create flag creates a new branch from --base — the default branch unless specified. Without --create, the branch must already exist. Switching to a remote branch (e.g., wt switch feature when only origin/feature exists) creates a local tracking branch.
One rule decides the upstream, whatever branch.autoSetupMerge is set to: a new branch tracks the remote branch it starts from only when the two share a name. Switching to origin/feature shares it, so that branch tracks. --create need not: --create release --base origin/release tracks origin/release, while --create feature --base origin/release — and the bare --base release that resolves to it — gets no upstream. Git’s default would have feature track origin/release, so under push.default = upstream a bare git push would push the new work to release. Publishing such a branch takes git push --set-upstream origin <branch>, or git’s push.autoSetupRemote = true set once, after which a bare git push from the new worktree publishes it and configures its tracking.
Creating worktrees
Section titled “Creating worktrees”If the branch already has a worktree, wt switch changes directories to it. Otherwise, it creates one:
- Runs pre-switch hooks, blocking until complete
- Creates worktree at configured path
- Switches to new directory
- Runs pre-start hooks, blocking until complete
- Spawns post-start and post-switch hooks in the background
wt switch feature # Existing branch → creates worktreewt switch --create feature # New branch and worktreewt switch --create fix --base release # New branch from releasewt switch --create temp --no-hooks # Skip hooksNaming a worktree
Section titled “Naming a worktree”Worktrees are addressed by branch name, and every argument that takes one also accepts the path of the worktree itself — resolved after the branch, so a directory never shadows a branch sharing its name. A path names what a branch cannot: a detached worktree, or one of two checkouts of the same branch. Relative paths resolve against -C and a leading ~ against the home directory, so a path worktrunk printed can be pasted back.
Shortcuts
Section titled “Shortcuts”| Shortcut | Meaning |
|---|---|
^ | Default branch (main/master) |
@ | Current branch/worktree |
- | Previous worktree (like cd -) |
pr:{N} | GitHub PR #N’s branch |
mr:{N} | GitLab MR !N’s branch |
wt switch - # Back to previouswt switch ^ # Default branch worktreewt switch --create fix --base=@ # Branch from current HEADwt switch --create fix --base=pr:123 # Branch from PR #123's headwt switch pr:123 # PR #123's branchwt switch mr:101 # MR !101's branchShortcuts also apply to --base. For a fork PR/MR, the head commit is fetched and used as the base SHA without creating a tracking branch.
Interactive picker
Section titled “Interactive picker”When called without arguments, wt switch opens an interactive picker to browse and select worktrees with live preview. The candidate set widens with --branches (local branches without worktrees), --remotes (remote branches), and --prs (open PRs/MRs — see below).
The CI column shows each row’s PR/MR CI and review status, the same as wt list --full.
Keybindings:
| Key | Action |
|---|---|
↑/↓ | Navigate worktree list |
| (type) | Filter worktrees |
Enter | Switch to selected worktree |
Alt-c | Create new worktree named as entered text |
Alt-x | Remove selected worktree/branch (never forces) |
Alt-y | Copy selected branch name to the clipboard |
Alt-o | Open the selected row’s PR/MR URL in the browser |
Alt-r | Refresh the list (pick up worktrees created elsewhere) |
Esc | Cancel |
Alt-1–Alt-8 | Jump to a preview tab |
Tab/Shift-Tab | Cycle available preview tabs forward/backward |
Alt-p | Toggle preview panel |
Ctrl-u/Ctrl-d | Scroll preview up/down |
Alt-o is a no-op on a row with no PR/MR (or whose status hasn’t loaded yet).
Alt-x is a no-op on the current worktree (the @ row) — removing the worktree in use would have to switch elsewhere first, so switch away and remove it from there.
Each row filters by its branch, path, and — when it has a PR/MR — the PR/MR’s number, title, and author, the same fields whether the PR is checked out (a worktree row) or listed via --prs. Plain digits go to the filter, so a number can be typed directly and the preview tabs move to Alt.
Typing a gutter sigil filters by row kind: + narrows to linked worktrees and @ to the current worktree. The other sigils don’t filter cleanly — ^ and | are skim’s prefix-anchor and OR query operators (so ^ matches every row and | none), and / matches most rows because every worktree path contains it.
Preview tabs:
- diff — One net diff from the comparison base through the current worktree: committed, staged, unstaged, and untracked changes
- working — Staged, unstaged, and untracked changes against
HEAD - committed — Committed changes since the comparison base
- log — Recent commits; commits already on the default branch have dimmed hashes
- remote⇅ — Ahead/behind diff vs upstream tracking branch
- summary — LLM-generated branch summary; requires
[list] summary = trueandcommit.generation - pr — The selected row’s PR/MR, for any row whose branch has one
- comments — The PR/MR’s comment thread, fetched from the forge for any row whose branch has one
The comparison base is the merge-base with the default branch, or with its upstream when the local default branch lags. The picker opens on diff for local rows and pr for a PR/MR listed by --prs but not available locally. Tab and Shift-Tab skip tabs without content; Alt-1 through Alt-8 open any tab directly. After you choose a tab, that choice stays active while you navigate.
On narrow previews the tab bar compacts to digits — only the active tab keeps its label — so every Alt-N accelerator stays visible.
Pager configuration: The preview panel pipes diff output through git’s pager. Override in user config:
[switch.picker]pager = "delta --paging=never --width=$COLUMNS"Pull requests and merge requests
Section titled “Pull requests and merge requests”The pr:<number> / mr:<number> shortcut and the PR/MR’s web URL both resolve to its branch. For same-repo PRs/MRs, worktrunk switches to the branch directly. For fork PRs/MRs, it fetches the ref (refs/pull/N/head or refs/merge-requests/N/head) and configures pushRemote to the fork URL.
wt switch pr:101 # GitHub PR #101wt switch https://github.com/owner/repo/pull/101 # ...the same PR, by URLwt switch mr:101 # GitLab MR !101wt switch https://gitlab.com/owner/repo/-/merge_requests/101 # ...the same MR, by URLwt switch --prs # Browse open PRs/MRs in the pickerBoth work anywhere a branch is accepted, including --base. The --create flag cannot be used with a PR/MR reference since the branch already exists.
If the PR or MR is on a fork, the local branch uses its branch name directly, so git push works normally. A pre-existing local branch with that name tracking something else requires renaming first.
The --prs flag adds the repository’s open PRs (GitHub) or MRs (GitLab) to the interactive picker — only the ones not already there: a PR whose branch is already shown (as a worktree, or a local or remote branch) isn’t listed twice, so --prs only adds the rest and the two pickers differ solely by those extra rows. Each added row resolves to the same pr:/mr: shortcut, so selecting one fetches the ref and switches to its branch. A --prs row has no local worktree, so its pr and comments preview tabs load the PR/MR’s metadata and comments from the forge in the background. The log tab uses a local git log — graph and merge-base dimming included — whenever the head commit is already in the object store (a same-repo PR off a fetched remote), falling back to a flat forge-fetched commit list otherwise.
Requires gh (GitHub), glab (GitLab), or an equivalent CLI installed and authenticated; see forge platform for Gitea, Azure DevOps, and other supported platforms.
When wt switch fails
Section titled “When wt switch fails”- Branch doesn’t exist — Use
--create, or checkwt list --branches - Path occupied — Another worktree is at the target path; switch to it or remove it
- Stale directory — Use
--clobberto remove a non-worktree directory at the target path
To change which branch a worktree is on, use git switch inside that worktree.
See also
Section titled “See also”wt list— View all worktreeswt remove— Delete worktrees when donewt merge— Integrate changes back to the default branch
Command reference
Section titled “Command reference”wt switch - Switch to a worktree; create if neededUsage: wt switch [OPTIONS] [BRANCH] [-- <EXECUTE_ARGS>...]Arguments:[BRANCH]Branch, worktree path, shortcut, or PR/MR URLOpens interactive picker if omitted. Shortcuts: ^ (default branch), - (previous), @(current), pr:{N} (GitHub PR), mr:{N} (GitLab MR)[EXECUTE_ARGS]...Additional arguments for --execute command (after --)Each argument is expanded for templates and passed directly to the program.Options:-c, --createCreate a new branch-b, --base <BASE>Base branchDefaults to default branch. Supports the same shortcuts as the branch argument: ^, @, -,pr:{N}, mr:{N}.-x, --execute <EXECUTE>Program to run after switchRuns one external program after switching, with full terminal control. Arguments after --go directly to that program without Worktrunk shell parsing. Program lookup and argumentdecoding follow the operating system. Shell syntax requires an explicit shell, for example-x sh -- -c 'npm install && npm test'. On Windows, shell shims need their extension (-xcode.cmd) or an explicit shell such as -x cmd.exe -- /C code.Without a branch argument, the interactive picker opens and the command runs against theselected worktree — so wt switch -x claude picks a worktree, then launches Claude Codethere. With --no-cd, the program starts in the invoking directory instead.Supports hook template variables ({{ branch }}, {{ worktree_path }}, etc.) and filters. {{base }} and {{ base_worktree_path }} describe the source: the selected base with --create,or the invoking worktree when switching to an existing worktree.A variable inside a shell body is substituted before that shell parses it, so a path withspaces splits into several arguments. Pass it as a separate argument instead — sh bindsthe first one to $0, so the path arrives as $1:wt switch feature -x sh -- -c 'cd "$1" && npm test' sh '{{ worktree_path }}'alias wsc='wt switch --create -x claude'wsc feature-branch -- 'Fix GH #322'Then wsc feature-branch creates the worktree and launches Claude Code. Arguments after --are passed to the command, so wsc feature -- 'Fix GH #322' runs claude 'Fix GH #322',starting Claude with a prompt.Template example: -x code -- '{{ worktree_path }}' opens VS Code at the worktree, -x tmux-- new -s '{{ branch | sanitize }}' starts a tmux session named after the branch.--clobberRemove stale paths at target--no-cdSkip directory change after switchingHooks still run normally. Useful when hooks handle navigation (e.g., tmux workflows) orfor CI/automation. --execute also starts in the invoking directory. Use --cd to override.-h, --helpPrint help (see a summary with '-h')Picker Options:--branchesInclude branches without worktrees--remotesInclude remote branches--prsInclude open PRs/MRsAutomation:--no-hooksSkip hooks--format <FORMAT>Output formatJSON prints structured result to stdout. Designed for tool integration (e.g., Claude CodeWorktreeCreate hooks).Global Options:-C <path>Working directory for this command--config <path>User config file path--config-set <toml>Override config with inline TOML, e.g. --config-set list.full=true (repeatable)-v, --verbose...Verbose output (-v: info logs + hook/alias template variables on stderr; -vv: also debuglogs and raw subprocess output written to .git/wt/logs/). Set WORKTRUNK_VERBOSE=0|1|2 toapply the same level everywhere — including shell completion, which no flag can reach-y, --yesSkip approval prompts