A Git worktree manager for trunk-based development
worktrunk (wt) is a Git worktree manager designed for trunk-based development workflows.
It simplifies creating, switching between, and managing Git worktrees, making it easy to
work on multiple features or branches simultaneously without the overhead of stashing
or switching branches in a single working directory.
Experimental --reap flag for wt remove: wt remove --reap terminates processes still running in the worktree (a post-start dev server, a file watcher, a language server) before removing it, freeing the ports and file handles they hold. Processes are discovered by working directory and terminated with SIGTERM, then SIGKILL for survivors; the list prints before any signal is sent. A process holding a controlling terminal (an interactive shell, a terminal editor with unsaved buffers) is never touched. Unix only. Docs (#3396)
wt switch -x without a branch opens the picker: --execute no longer requires a branch argument — wt switch -x claude opens the interactive picker and runs the command against the selected worktree. It composes with every picker mode (--branches, --remotes, --prs), and the picker path shares the same pipeline as the argument path, so hooks, approval, and template expansion behave identically. (#3394, closes #3370, thanks @gbcreation for the request)
wt config state logs profile groups subprocess time by worktree: The report gained a BY CONTEXT table (and a by_context array in --format=json) — subprocess time per context, typically the worktree name — so a slow parallel phase can be attributed to the worktree causing it without exporting the trace to an external tool. (#3403)
-vv diagnostics surface pager and terminal environment: The diagnostic report (.git/wt/logs/diagnostic.md, written on every -vv run) gained an "Environment variables" section listing a curated, non-secret allowlist of the pager / terminal / locale knobs (PAGER, GIT_PAGER, TERM, COLUMNS, NO_COLOR, LANG, …) plus git's resolved core.pager. These are the inputs that most often explain a rendering bug — like a pager interaction suspending wt config show (#3322) — and they were previously invisible in the report. The list is a strict allowlist, never a blanket env dump, so no credential-bearing variable can leak into an uploaded report.
wt config update pins [list] json-schema while unset: The schema hint from 0.66.0 now comes with the standard one-command fix — wt config update pins json-schema = 1 (the behavior-preserving choice) when the key is unset, and the hint offers the command only when running it would actually write the pin. (#3411)
Fixed
wt switch no longer crashes on ragged tables in PR comments: A PR/MR comment table with more cells in a data row than in its header could panic termimad's column fitter at narrow widths, and because the comments preview renders on a background worker, the panic aborted the whole picker. The table render is now contained; the preview falls back to the table's plain text. (#3408, closes #3407, thanks @ortonomy for reporting)
wt config show no longer suspends on the zsh completion probe: The interactive zsh probe that detects a missing compinit claims the terminal foreground when job control is on; a slow or prompting zsh startup could hit the probe's kill-on-timeout before the foreground was restored, leaving wt in a background process group and its pager suspended with suspended (tty output). Both interactive probes now run with job control disabled (zsh +m), so a timed-out probe can't strand the terminal. (#3327, closes #3322, thanks @karmeleon for reporting)
wt step for-each and the --execute fallback no longer inherit wt's GIT_* discovery vars: The command that for-each runs in each worktree — and the --execute payload, when wt executes it directly because shell integration isn't active — now discovers its repository from the worktree wt placed it in, rather than an inherited GIT_DIR/GIT_WORK_TREE. Previously such a command's git calls resolved against the one inherited repo (e.g. the invoking worktree, when wt runs as a !wt git alias from a linked worktree) while the per-worktree headers claimed otherwise. This extends the hook-spawn scrub from #3374 to the remaining spawn sites that relocate a user command into a wt-chosen worktree; aliases and commit.generation commands run in the user's own context and keep the inherited environment. (#3400, #3373)
wt list holds steady when the shell prompt returns: The progressive table reserves two blank rows beneath its footer, so the multi-line prompt printed at exit renders into pre-scrolled rows instead of scrolling the settled table up. (#3409)
JSON schema 2: no self-relation on a remote-only default-branch row: wt list --format=json with schema 2 gave a remote-only row of the default branch (origin/main) a self-referential relation; the default-branch check now compares the remote-stripped branch name. (#3383)
Documentation
Code Signing Policy page: A new page documents Worktrunk's code-signing policy for the Windows binaries under the SignPath Foundation open-source program: certificate provenance, the signing pipeline, and per-release approval. Signing addresses Microsoft Defender's false positives on unsigned native binaries. Docs (#3366, thanks @bemnlam for reporting #3355)
Internal
Claude plugin hooks are Claude-scoped: The plugin's hooks file is renamed hooks.json → claude-hooks.json so Codex's convention discovery can't pick up Claude's hooks, hardening the Codex scoping shipped in 0.66.0. (#3382, thanks @ofek for the suggestion)
skim 5.0: The picker's fuzzy-finder library moves from 4.10 to 5.0, dropping roughly 1,000 lines of transitive dependencies from the lockfile. (#3378)
Prune benchmarks: A rust-repo-scale prune fixture, Criterion benches, and trace spans over the removal path. (#3401)
Nix flake test sandbox provides lsof, and flake changes now trigger the nix-flake CI job. (#3410)
Install worktrunk 0.67.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/max-sixty/worktrunk/releases/download/v0.67.0/worktrunk-installer.sh | sh && wt config shell install
Install prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/max-sixty/worktrunk/releases/download/v0.67.0/worktrunk-installer.ps1 | iex"; git-wt config shell install
Install prebuilt binaries via Homebrew
brew install worktrunk && wt config shell install
Download worktrunk 0.67.0
────────────────────────────────────────────────┬───────────────────┬─────────────
File │Platform │Checksum
────────────────────────────────────────────────┼───────────────────┼─────────────
worktrunk-aarch64-apple-darwin.tar.xz │Apple Silicon macOS│checksum
────────────────────────────────────────────────┼───────────────────┼─────────────
worktrunk-x86_64-apple-darwin.tar.xz │Intel macOS │checksum
────────────────────────────────────────────────┼───────────────────┼─────────────
worktrunk-x86_64-pc-windows-msvc.zip │x64 Windows │checksum
────────────────────────────────────────────────┼───────────────────┼─────────────
worktrunk-aarch64-unknown-linux-musl.tar.xz │ARM64 MUSL Linux │checksum
────────────────────────────────────────────────┼───────────────────┼─────────────
worktrunk-x86_64-unknown-linux-musl.tar.xz │x64 MUSL Linux │checksum
────────────────────────────────────────────────┴───────────────────┴─────────────
Install via Cargo
cargo install worktrunk && wt config shell install
Install via Winget (Windows)
winget install max-sixty.worktrunk && git-wt config shell install
Install via AUR (Arch Linux)
paru worktrunk-bin && wt config shell install