wt supports an optional TOML configuration file. Use wt config commands to manage it:
wt config init # Create a default config file
wt config init --force # Overwrite existing config file
wt config show # Show effective configuration with sources
wt config path # Print the config file pathFile location (in order of priority):
--configflag:wt --config /path/to/config.toml <command>WT_CONFIGenvironment variable- Default:
~/.config/wt/config.toml(respects$XDG_CONFIG_HOME;%AppData%\wt\config.tomlon Windows)
Example config file (~/.config/wt/config.toml):
# Root directory for worktrees (default: ~/dev/worktrees)
root = "~/projects/worktrees"
# Worktree placement strategy
strategy = "sibling-repo"
# Separator replaces "/" and "\" in value variables ({.branch}, {.repo.Owner}, {.env.*})
# Default "/" preserves slashes (nested dirs). Set to "-" or "_" for flat paths.
# separator = "/"
# Custom pattern (used when strategy = "custom", or to override any strategy's default)
# pattern = "{.worktreeRoot}/{.repo.Name}/{.branch}"Configuration values are resolved in this order (highest priority first):
- CLI flags (
--config) - Environment variables (
WORKTREE_ROOT,WORKTREE_STRATEGY,WORKTREE_PATTERN,WORKTREE_SEPARATOR) - Config file (
~/.config/wt/config.toml) - Built-in defaults
Run wt config show to see the effective value and source of each setting.
By default, worktrees are created at ~/dev/worktrees/<repo>/{.branch} using the global strategy.
Available pattern variables:
{.repo.Name}repo name{.repo.Main}main branch worktree path (path variable, not transformed by separator){.repo.Owner}repo owner/group (from origin URL){.repo.Host}git host (from origin URL){.branch}git branch name{.worktreeRoot}value ofWORKTREE_ROOT(path variable, not transformed by separator){.env.VARNAME}value of environment variableVARNAME(e.g.{.env.USER},{.env.HOME})
Default patterns per strategy:
| Strategy | Description | Default pattern |
|---|---|---|
global |
worktrees under a global directory | {.worktreeRoot}/{.repo.Name}/{.branch} |
sibling-repo |
worktrees next to the main repo directory | {.repo.Main}/../{.repo.Name}-{.branch} |
parent-branches |
branches as siblings of main | {.repo.Main}/../{.branch} |
parent-worktrees |
branches under <repo>.worktrees/ |
{.repo.Main}/../{.repo.Name}.worktrees/{.branch} |
parent-dotdir |
branches under .worktrees/ next to main |
{.repo.Main}/../.worktrees/{.branch} |
inside-dotdir |
branches under .worktrees/ inside main |
{.repo.Main}/.worktrees/{.branch} |
custom |
user-defined pattern | WORKTREE_PATTERN |
The separator setting controls how / and \ characters in value variables ({.branch}, {.repo.Owner}, {.env.*}) are replaced. Path variables ({.repo.Main}, {.worktreeRoot}) are never transformed.
| Separator | Branch feat/foo becomes |
Use case |
|---|---|---|
/ (default) |
feat/foo (nested dirs) |
Standard layout |
- |
feat-foo (flat) |
Sibling-repo, flat directories |
_ |
feat_foo (flat) |
Alternative flat layout |
"" |
featfoo |
Compact (rarely used) |
The default macOS APFS setup is case-insensitive. That means paths such as
Feature/foo and feature/bar share the same first path component from the
filesystem's point of view, even though Git branch names are case-sensitive.
With the default separator, branch names with slashes become nested directories:
Feature/make-it-work -> ~/dev/worktrees/repo/Feature/make-it-work
feature/add-logging -> ~/dev/worktrees/repo/feature/add-logging
On a case-insensitive filesystem, Feature and feature refer to the same
directory. This can make wt create, wt checkout, wt remove, shell
completion, and manual git checkout commands appear to disagree about the
current branch or worktree path. When wt detects this before creating a
worktree, it prints a warning with the colliding path component.
If your repositories use mixed-case branch prefixes such as Feature/..., prefer
a flat path layout:
separator = "-"That maps branches to paths like:
Feature/make-it-work -> ~/dev/worktrees/repo/Feature-make-it-work
feature/add-logging -> ~/dev/worktrees/repo/feature-add-logging
Changing separator affects newly created path calculations. Run wt migrate
or recreate existing worktrees if you want current worktrees to use the new
layout.
This avoids collisions between unrelated branch prefixes such as Feature/...
and feature/.... It does not make case-only branch names safe: Feature/foo
and feature/foo still map to names that collide on a case-insensitive
filesystem. Avoid case-only branch differences, or place the repository and
worktree root on a case-sensitive filesystem.
Hooks let you run custom commands before or after wt operations. Define them in the [hooks] section of your config file:
Available hooks:
| Hook | When it runs |
|---|---|
pre_create / post_create |
Before/after wt create |
pre_checkout / post_checkout |
Before/after wt checkout (alias wt co) |
pre_remove / post_remove |
Before/after wt remove (alias wt rm) |
pre_pr / post_pr |
Before/after wt pr |
pre_mr / post_mr |
Before/after wt mr |
Checkout hooks (pre_checkout / post_checkout) run both when a new worktree is created and when checking out an existing worktree. Create and remove hooks run only when a worktree is actually created or removed.
Environment variables available in hook commands:
| Variable | Description |
|---|---|
$WT_PATH |
Worktree path being created/removed |
$WT_BRANCH |
Branch name |
$WT_MAIN |
Path to the main worktree |
$WT_REPO_NAME |
Repository name |
$WT_REPO_HOST |
Git host (e.g. github.com) |
$WT_REPO_OWNER |
Repository owner/group |
Behavior:
- Pre-hooks abort the operation if any command exits non-zero
- Post-hooks print a warning on failure but do not fail the
wtcommand - Each hook is a list of shell commands executed via
sh -c(orcmd /con Windows) - Set
WT_HOOKS_DISABLED=1to skip all hooks (useful for scripting or CI)
Common patterns:
[hooks]
# Copy .env file to new worktrees (only if it exists in main)
post_create = ["test -f $WT_MAIN/.env && cp $WT_MAIN/.env $WT_PATH/.env || true"]
# Install dependencies after checkout
post_checkout = ["cd $WT_PATH && npm install"]
# Run cleanup before removing a worktree
pre_remove = ["cd $WT_PATH && npm run clean"]