wt step

Run individual operations. The building blocks of wt merge — commit, squash, rebase, push — plus standalone utilities.

Examples

Commit with LLM-generated message:

wt step commit

Manual merge workflow with review between steps:

wt step commit
wt step squash
wt step rebase
wt step push

Operations

See also

Command reference

wt step - Run individual operations

The building blocks of wt merge — commit, squash, rebase, push — plus standalone
utilities.

Usage: wt step [OPTIONS] <COMMAND>

Commands:
  commit        Stage and commit with LLM-generated message
  squash        Squash commits since branching
  push          Fast-forward target to current branch
  rebase        Rebase onto target
  diff          Show all changes since branching
  copy-ignored  Copy gitignored files to another worktree
  for-each      [experimental] Run command in each worktree
  promote       [experimental] Put a branch into the main worktree
  prune         [experimental] Remove worktrees merged into the default branch
  relocate      [experimental] Move worktrees to expected paths

Options:
  -h, --help
          Print help (see a summary with '-h')

Global Options:
  -C <path>
          Working directory for this command

      --config <path>
          User config file path

  -v, --verbose...
          Verbose output (-v: hooks, templates; -vv: debug report)

Subcommands

wt step commit

Stage and commit with LLM-generated message.

Stages all changes (including untracked files) and commits with an LLM-generated message.

Options

--stage

Controls what to stage before committing:

ValueBehavior
allStage all changes including untracked files (default)
trackedStage only modified tracked files
noneDon't stage anything, commit only what's already staged
wt step commit --stage=tracked

Configure the default in user config:

[commit]
stage = "tracked"

--show-prompt

Output the rendered LLM prompt to stdout without running the command. Useful for inspecting prompt templates or piping to other tools:

# Inspect the rendered prompt
wt step commit --show-prompt | less

# Pipe to a different LLM
wt step commit --show-prompt | llm -m gpt-5-nano

Command reference

wt step commit - Stage and commit with LLM-generated message

Usage: wt step commit [OPTIONS]

Options:
  -y, --yes
          Skip approval prompts

      --no-verify
          Skip hooks

      --stage <STAGE>
          What to stage before committing [default: all]

          Possible values:
          - all:     Stage everything: untracked files + unstaged tracked
            changes
          - tracked: Stage tracked changes only (like git add -u)
          - none:    Stage nothing, commit only what's already in the index

      --show-prompt
          Show prompt without running LLM

          Outputs the rendered prompt to stdout for debugging or manual piping.

  -h, --help
          Print help (see a summary with '-h')

Global Options:
  -C <path>
          Working directory for this command

      --config <path>
          User config file path

  -v, --verbose...
          Verbose output (-v: hooks, templates; -vv: debug report)

wt step squash

Squash commits since branching. Stages changes and generates message with LLM.

Stages all changes (including untracked files), then squashes all commits since diverging from the target branch into a single commit with an LLM-generated message.

Options

--stage

Controls what to stage before squashing:

ValueBehavior
allStage all changes including untracked files (default)
trackedStage only modified tracked files
noneDon't stage anything, squash only committed changes
wt step squash --stage=none

Configure the default in user config:

[commit]
stage = "tracked"

--show-prompt

Output the rendered LLM prompt to stdout without running the command. Useful for inspecting prompt templates or piping to other tools:

wt step squash --show-prompt | less

Command reference

wt step squash - Squash commits since branching

Stages changes and generates message with LLM.

Usage: wt step squash [OPTIONS] [TARGET]

Arguments:
  [TARGET]
          Target branch

          Defaults to default branch.

Options:
  -y, --yes
          Skip approval prompts

      --no-verify
          Skip hooks

      --stage <STAGE>
          What to stage before committing [default: all]

          Possible values:
          - all:     Stage everything: untracked files + unstaged tracked
            changes
          - tracked: Stage tracked changes only (like git add -u)
          - none:    Stage nothing, commit only what's already in the index

      --show-prompt
          Show prompt without running LLM

          Outputs the rendered prompt to stdout for debugging or manual piping.

  -h, --help
          Print help (see a summary with '-h')

Global Options:
  -C <path>
          Working directory for this command

      --config <path>
          User config file path

  -v, --verbose...
          Verbose output (-v: hooks, templates; -vv: debug report)

wt step copy-ignored

Copy gitignored files to another worktree. Eliminates cold starts by copying build caches and dependencies.

Git worktrees share the repository but not untracked files. This command copies gitignored files to another worktree, eliminating cold starts.

Setup

Add to the project config:

# .config/wt.toml
[post-start]
copy = "wt step copy-ignored"

What gets copied

All gitignored files are copied by default. Tracked files are never touched.

To limit what gets copied, create .worktreeinclude with gitignore-style patterns. Files must be both gitignored and in .worktreeinclude:

# .worktreeinclude
.env
node_modules/
target/

Common patterns

TypePatterns
Dependenciesnode_modules/, .venv/, target/, vendor/, Pods/
Build caches.cache/, .next/, .parcel-cache/, .turbo/
Generated assetsImages, ML models, binaries too large for git
Environment files.env (if not generated per-worktree)

Features

Performance

Reflink copies share disk blocks until modified — no data is actually copied. For a 14GB target/ directory:

CommandTime
cp -R (full copy)2m
cp -Rc / wt step copy-ignored20s

Uses per-file reflink (like cp -Rc) — copy time scales with file count.

Use the post-start hook so the copy runs in the background. Use post-create instead if subsequent hooks or --execute command need the copied files immediately.

Language-specific notes

Rust

The target/ directory is huge (often 1-10GB). Copying with reflink cuts first build from ~68s to ~3s by reusing compiled dependencies.

Node.js

node_modules/ is large but mostly static. If the project has no native dependencies, symlinks are even faster:

[post-create]
deps = "ln -sf {{ primary_worktree_path }}/node_modules ."

Python

Virtual environments contain absolute paths and can't be copied. Use uv sync instead — it's fast enough that copying isn't worth it.

Behavior vs Claude Code on desktop

The .worktreeinclude pattern is shared with Claude Code on desktop, which copies matching files when creating worktrees. Differences:

Command reference

wt step copy-ignored - Copy gitignored files to another worktree

Eliminates cold starts by copying build caches and dependencies.

Usage: wt step copy-ignored [OPTIONS]

Options:
      --from <FROM>
          Source worktree branch

          Defaults to main worktree.

      --to <TO>
          Destination worktree branch

          Defaults to current worktree.

      --dry-run
          Show what would be copied

      --force
          Overwrite existing files in destination

  -h, --help
          Print help (see a summary with '-h')

Global Options:
  -C <path>
          Working directory for this command

      --config <path>
          User config file path

  -v, --verbose...
          Verbose output (-v: hooks, templates; -vv: debug report)

wt step for-each

[experimental] Run command in each worktree. Executes sequentially with real-time output; continues on failure.

Executes a command sequentially in every worktree with real-time output. Continues on failure and shows a summary at the end.

Context JSON is piped to stdin for scripts that need structured data.

Template variables

All variables are shell-escaped. See wt hook template variables for the complete list and filters.

Examples

Check status across all worktrees:

wt step for-each -- git status --short

Run npm install in all worktrees:

wt step for-each -- npm install

Use branch name in command:

wt step for-each -- "echo Branch: {{ branch }}"

Pull updates in worktrees with upstreams (skips others):

git fetch --prune && wt step for-each -- '[ "$(git rev-parse @{u} 2>/dev/null)" ] || exit 0; git pull --autostash'

Note: This command is experimental and may change in future versions.

Command reference

wt step for-each - [experimental] Run command in each worktree

Executes sequentially with real-time output; continues on failure.

Usage: wt step for-each [OPTIONS] -- <ARGS>...

Arguments:
  <ARGS>...
          Command template (see --help for all variables)

Options:
  -h, --help
          Print help (see a summary with '-h')

Global Options:
  -C <path>
          Working directory for this command

      --config <path>
          User config file path

  -v, --verbose...
          Verbose output (-v: hooks, templates; -vv: debug report)

wt step prune

[experimental] Remove worktrees merged into the default branch.

Bulk-removes worktrees and branches that are integrated into the default branch, using the same criteria as wt remove's branch cleanup. Stale worktree entries are cleaned up too.

In wt list, candidates show _ (same commit) or (content integrated). Run --dry-run to preview. See wt remove --help for the full integration criteria.

Locked worktrees and the main worktree are always skipped. The current worktree is removed last, triggering cd to the primary worktree. Pre-remove and post-remove hooks run for each removal.

Min-age guard

Worktrees younger than --min-age (default: 1 hour) are skipped. This prevents removing a worktree just created from the default branch — it looks "merged" because its branch points at the same commit.

wt step prune --min-age=0s     # no age guard
wt step prune --min-age=2d     # skip worktrees younger than 2 days

Examples

Preview what would be removed:

wt step prune --dry-run

Remove all merged worktrees:

wt step prune

Command reference

wt step prune - [experimental] Remove worktrees merged into the default branch

Usage: wt step prune [OPTIONS]

Options:
      --dry-run
          Show what would be removed

  -y, --yes
          Skip approval prompts

      --min-age <MIN_AGE>
          Skip worktrees younger than this

          [default: 1h]

      --foreground
          Run removal in foreground (block until complete)

  -h, --help
          Print help (see a summary with '-h')

Global Options:
  -C <path>
          Working directory for this command

      --config <path>
          User config file path

  -v, --verbose...
          Verbose output (-v: hooks, templates; -vv: debug report)

wt step relocate

[experimental] Move worktrees to expected paths. Relocates worktrees whose path doesn't match the worktree-path template.

Moves worktrees to match the configured worktree-path template.

Examples

Preview what would be moved:

wt step relocate --dry-run

Move all mismatched worktrees:

wt step relocate

Auto-commit and clobber blockers (never fails):

wt step relocate --commit --clobber

Move specific worktrees:

wt step relocate feature bugfix

Swap handling

When worktrees are at each other's expected locations (e.g., alpha at repo.beta and beta at repo.alpha), relocate automatically resolves this by using a temporary location.

Clobbering

With --clobber, non-worktree paths at target locations are moved to <path>.bak-<timestamp> before relocating.

Main worktree behavior

The main worktree can't be moved with git worktree move. Instead, relocate switches it to the default branch and creates a new linked worktree at the expected path. Untracked and gitignored files remain at the original location.

Skipped worktrees

Note: This command is experimental and may change in future versions.

Command reference

wt step relocate - [experimental] Move worktrees to expected paths

Relocates worktrees whose path doesn't match the worktree-path template.

Usage: wt step relocate [OPTIONS] [BRANCHES]...

Arguments:
  [BRANCHES]...
          Worktrees to relocate (defaults to all mismatched)

Options:
      --dry-run
          Show what would be moved

      --commit
          Commit uncommitted changes before relocating

      --clobber
          Backup non-worktree paths at target locations

          Moves blocking paths to <path>.bak-<timestamp>.

  -h, --help
          Print help (see a summary with '-h')

Global Options:
  -C <path>
          Working directory for this command

      --config <path>
          User config file path

  -v, --verbose...
          Verbose output (-v: hooks, templates; -vv: debug report)