mirror of
https://github.com/max-sixty/worktrunk.git
synced 2026-09-14 20:00:38 +08:00
667c6efaf0
Requested by @max-sixty in [#3809](https://github.com/max-sixty/worktrunk/issues/3809#issuecomment-5273484502) — a couple of words clarifying that `Alt-x`'s removal is safe-only. The keybinding table read `Remove selected worktree/branch`, which doesn't say the removal never forces; that's what sent the reporter looking for a force-remove that isn't there. The picker hardcodes the safe path — [`prepare_removal`](https://github.com/max-sixty/worktrunk/blob/7a2a3e003e7eed138ff5f2dcd2296f6bbd8e86d4/src/commands/picker/mod.rs#L323-L330) passes `BranchDeletionMode::SafeDelete` and `force_worktree: false`. Deliberately scoped to the table cell, per the "(only)" in the request. The bigger question — whether `Alt-x` should ever pass `-D` — is still open on the issue and isn't touched here. Primary source is `after_long_help` in `src/cli/mod.rs`; the three mirrors and the `--help` snapshot are regenerated. Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
258 lines
14 KiB
Markdown
258 lines
14 KiB
Markdown
+++
|
||
title = "wt switch"
|
||
description = "Switch to a worktree; create if needed."
|
||
weight = 10
|
||
|
||
[extra]
|
||
group = "Commands"
|
||
+++
|
||
|
||
<!-- ⚠️ AUTO-GENERATED from `wt switch --help-page` — edit src/cli/mod.rs to update -->
|
||
|
||
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.
|
||
|
||
<figure class="demo">
|
||
<picture>
|
||
<source srcset="/assets/docs/dark/wt-switch.gif" media="(prefers-color-scheme: dark)">
|
||
<img src="/assets/docs/light/wt-switch.gif" alt="wt switch demo" width="1600" height="900">
|
||
</picture>
|
||
</figure>
|
||
|
||
## Examples
|
||
|
||
{{ terminal(cmd="wt switch feature-auth # Switch to worktree|||wt switch - # Previous worktree (like cd -)|||wt switch --create new-feature # Create new branch and worktree|||wt switch --create hotfix --base production|||wt switch pr:123 # Switch to PR #123's branch|||wt switch https://github.com/owner/repo/pull/123 # ...or paste the PR's URL") }}
|
||
|
||
## 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.
|
||
|
||
## Creating worktrees
|
||
|
||
If the branch already has a worktree, `wt switch` changes directories to it. Otherwise, it creates one:
|
||
|
||
1. Runs [pre-switch hooks](@/hook.md#hook-types), blocking until complete
|
||
2. Creates worktree at configured path
|
||
3. Switches to new directory
|
||
4. Runs [pre-start hooks](@/hook.md#hook-types), blocking until complete
|
||
5. Spawns [post-start](@/hook.md#hook-types) and [post-switch hooks](@/hook.md#hook-types) in the background
|
||
|
||
{{ terminal(cmd="wt switch feature # Existing branch → creates worktree|||wt switch --create feature # New branch and worktree|||wt switch --create fix --base release # New branch from release|||wt switch --create temp --no-hooks # Skip hooks") }}
|
||
|
||
## 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
|
||
|
||
| 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 |
|
||
|
||
{{ terminal(cmd="wt switch - # Back to previous|||wt switch ^ # Default branch worktree|||wt switch --create fix --base=@ # Branch from current HEAD|||wt switch --create fix --base=pr:123 # Branch from PR #123's head|||wt switch pr:123 # PR #123's branch|||wt switch mr:101 # MR !101's branch") }}
|
||
|
||
Shortcuts 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
|
||
|
||
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`](@/list.md).
|
||
|
||
<figure class="demo">
|
||
<picture>
|
||
<source srcset="/assets/docs/dark/wt-switch-picker.gif" media="(prefers-color-scheme: dark)">
|
||
<img src="/assets/docs/light/wt-switch-picker.gif" alt="wt switch picker demo" width="1600" height="800">
|
||
</picture>
|
||
</figure>
|
||
|
||
**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-7` | Jump to a preview tab |
|
||
| `Tab`/`Shift-Tab` | Cycle 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:**
|
||
|
||
1. **HEAD±** — Diff of uncommitted changes
|
||
2. **log** — Recent commits; commits already on the default branch have dimmed hashes
|
||
3. **main…±** — Diff of changes since the merge-base with the default branch
|
||
4. **remote⇅** — Ahead/behind diff vs upstream tracking branch
|
||
5. **summary** — LLM-generated branch summary; requires `[list] summary = true` and [`commit.generation`](@/config.md#commit)
|
||
6. **pr** — The selected row's PR/MR, for any row whose branch has one
|
||
7. **comments** — The PR/MR's comment thread, fetched from the forge for any row whose branch has one
|
||
|
||
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:
|
||
|
||
```toml
|
||
[switch.picker]
|
||
pager = "delta --paging=never --width=$COLUMNS"
|
||
```
|
||
|
||
## 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.
|
||
|
||
{{ terminal(cmd="wt switch pr:101 # GitHub PR #101|||wt switch https://github.com/owner/repo/pull/101 # ...the same PR, by URL|||wt switch mr:101 # GitLab MR !101|||wt switch https://gitlab.com/owner/repo/-/merge_requests/101 # ...the same MR, by URL|||wt switch --prs # Browse open PRs/MRs in the picker") }}
|
||
|
||
Both 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](@/config.md#forge-platform) for Gitea, Azure DevOps, and other supported platforms.
|
||
|
||
## When wt switch fails
|
||
|
||
- **Branch doesn't exist** — Use `--create`, or check `wt list --branches`
|
||
- **Path occupied** — Another worktree is at the target path; switch to it or remove it
|
||
- **Stale directory** — Use `--clobber` to 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
|
||
|
||
- [`wt list`](@/list.md) — View all worktrees
|
||
- [`wt remove`](@/remove.md) — Delete worktrees when done
|
||
- [`wt merge`](@/merge.md) — Integrate changes back to the default branch
|
||
|
||
## Command reference
|
||
|
||
{% terminal() %}
|
||
wt switch - Switch to a worktree; create if needed
|
||
|
||
Usage: <b><span class=c>wt switch</span></b> <span class=c>[OPTIONS]</span> <span class=c>[BRANCH]</span> <b><span class=c>[--</span></b> <span class=c><EXECUTE_ARGS>...</span><b><span class=c>]</span></b>
|
||
|
||
<b><span class=g>Arguments:</span></b>
|
||
<span class=c>[BRANCH]</span>
|
||
Branch, worktree path, shortcut, or PR/MR URL
|
||
|
||
Opens interactive picker if omitted. Shortcuts: <b>^</b> (default branch), <b>-</b> (previous), <b>@</b>
|
||
(current), <b>pr:{N}</b> (GitHub PR), <b>mr:{N}</b> (GitLab MR)
|
||
|
||
<span class=c>[EXECUTE_ARGS]...</span>
|
||
Additional arguments for --execute command (after --)
|
||
|
||
Arguments after <b>--</b> are appended to the execute command. Each argument is expanded for
|
||
templates, then POSIX shell-escaped.
|
||
|
||
<b><span class=g>Options:</span></b>
|
||
<b><span class=c>-c</span></b>, <b><span class=c>--create</span></b>
|
||
Create a new branch
|
||
|
||
<b><span class=c>-b</span></b>, <b><span class=c>--base</span></b><span class=c> <BASE></span>
|
||
Base branch
|
||
|
||
Defaults to default branch. Supports the same shortcuts as the branch argument: <b>^</b>, <b>@</b>, <b>-</b>,
|
||
<b> pr:{N}</b>, <b>mr:{N}</b>.
|
||
|
||
<b><span class=c>-x</span></b>, <b><span class=c>--execute</span></b><span class=c> <EXECUTE></span>
|
||
Command to run after switch
|
||
|
||
Replaces the wt process with the command after switching, giving it full terminal control.
|
||
Useful for launching editors, AI agents, or other interactive tools.
|
||
|
||
Without a branch argument, the interactive picker opens and the command runs against the
|
||
selected worktree — so <b>wt switch -x claude</b> picks a worktree, then launches Claude Code
|
||
there.
|
||
|
||
Supports <u>hook template variables</u> (<b>{{ branch }}</b>, <b>{{ worktree_path }}</b>, etc.) and filters. <b>{{</b>
|
||
<b> base }}</b> and <b>{{ base_worktree_path }}</b> describe the source: the selected base with <b>--create</b>,
|
||
or the invoking worktree when switching to an existing worktree.
|
||
|
||
Especially useful with shell aliases:
|
||
|
||
<b><b>alias wsc='wt switch --create -x claude'</b></b>
|
||
<b>wsc feature-branch -- 'Fix GH #322'</b>
|
||
|
||
Then <b>wsc feature-branch</b> creates the worktree and launches Claude Code. Arguments after <b>--</b>
|
||
are passed to the command, so <b>wsc feature -- 'Fix GH #322'</b> runs <b>claude 'Fix GH #322'</b>,
|
||
starting Claude with a prompt.
|
||
|
||
Template example: <b>-x code -- '{{ worktree_path }}'</b> opens VS Code at the worktree, <b>-x tmux</b>
|
||
<b> -- new -s '{{ branch | sanitize }}'</b> starts a tmux session named after the branch.
|
||
|
||
<b><span class=c>--clobber</span></b>
|
||
Remove stale paths at target
|
||
|
||
<b><span class=c>--no-cd</span></b>
|
||
Skip directory change after switching
|
||
|
||
Hooks still run normally. Useful when hooks handle navigation (e.g., tmux workflows) or
|
||
for CI/automation. Use --cd to override.
|
||
|
||
<b><span class=c>-h</span></b>, <b><span class=c>--help</span></b>
|
||
Print help (see a summary with '-h')
|
||
|
||
<b><span class=g>Picker Options:</span></b>
|
||
<b><span class=c>--branches</span></b>
|
||
Include branches without worktrees
|
||
|
||
<b><span class=c>--remotes</span></b>
|
||
Include remote branches
|
||
|
||
<b><span class=c>--prs</span></b>
|
||
Include open PRs/MRs
|
||
|
||
<b><span class=g>Automation:</span></b>
|
||
<b><span class=c>--no-hooks</span></b>
|
||
Skip hooks
|
||
|
||
<b><span class=c>--format</span></b><span class=c> <FORMAT></span>
|
||
Output format
|
||
|
||
JSON prints structured result to stdout. Designed for tool integration (e.g., Claude Code
|
||
WorktreeCreate hooks).
|
||
|
||
[default: text]
|
||
[possible values: text, json]
|
||
|
||
<b><span class=g>Global Options:</span></b>
|
||
<b><span class=c>-C</span></b><span class=c> <path></span>
|
||
Working directory for this command
|
||
|
||
<b><span class=c>--config</span></b><span class=c> <path></span>
|
||
User config file path
|
||
|
||
<b><span class=c>--config-set</span></b><span class=c> <toml></span>
|
||
Override config with inline TOML, e.g. --config-set list.full=true (repeatable)
|
||
|
||
<b><span class=c>-v</span></b>, <b><span class=c>--verbose</span></b><span class=c>...</span>
|
||
Verbose output (-v: info logs + hook/alias template variables on stderr; -vv: also debug
|
||
logs and raw subprocess output written to .git/wt/logs/). Set WORKTRUNK_VERBOSE=0|1|2 to
|
||
apply the same level everywhere — including shell completion, which no flag can reach
|
||
|
||
<b><span class=c>-y</span></b>, <b><span class=c>--yes</span></b>
|
||
Skip approval prompts
|
||
{% end %}
|
||
|
||
<!-- END AUTO-GENERATED -->
|