装完必须执行 wt config shell install,否则命令无法切换目录;Windows 上 wt 与 Windows Terminal 冲突,Winget 版需用 git-wt;LLM 提交信息与 AI 摘要需另行配置模型

worktrunk
max-sixty活跃维护用 Rust 写的 Git worktree 管理命令行工具,专为并行 AI 编码代理设计,让多个 agent 各自在独立工作树里干活、互不干扰。
Worktrunk is a CLI for Git worktree management, designed for parallel AI agent workflows
brew install worktrunk && wt config shell installREADME 未说明,纯 CLI 工具,无 GPU 或显存要求
用分支名管理 git worktree 的 CLI,让多个 AI agent 并行开发互不干扰
用 Rust 写的 Git worktree 管理命令行工具,专为并行 AI 编码代理设计,让多个 agent 各自在独立工作树里干活、互不干扰。
核心能力
- 用 wt switch 按分支名切换或创建工作树
- wt switch -c -x claude 创建后直接启动 agent
- wt list 展示各分支改动、领先提交与远程状态
- wt merge 一条命令完成 squash、rebase、合并与清理
- 钩子自动化创建与合并流程,并共享构建缓存
容易踩的坑
- v0.81.00.81.0最新正式版2026-10-20 · 2026-10-20 21:28 UTC
Release Notes
Improved
-
Hooks can prompt: hooks that run serially in the foreground (
pre-*hooks,wt hook <type> --foreground) inherit wt's stdin, sogum confirm 'trust this worktree?' && mise trustworks as a hook. Concurrent and background hooks read EOF. (Breaking: hooks no longer receive their context as JSON on stdin; pass values as template arguments, or whole objects with the newtojsonfilter.wt step for-eachkeeps its JSON.) Docs (#3129, #4451, #4524, thanks @endigma for #3093) -
Experimental
wt switch --path: places one worktree outside theworktree-pathtemplate and keeps its branch name, as inwt switch --create feature/JIRA-1234 --path ../dark-mode. Commands reach it by branch or by path. Docs (#4317, thanks @christowiz for #1982) -
wt merge --branch: merges another worktree's branch without leaving the current worktree. Commit, squash, rebase, and hooks run in the source worktree, and cleanup removes it. Docs (#4360, thanks @liuyinchu) -
OpenCode 2 worktrees go through Worktrunk: after re-running
wt config plugins opencode install, worktrees OpenCode creates and removes usewt switch --createandwt remove, as the Claude Code plugin's do. OpenCode'sworktree.directorystops applying, and new branches start from the default branch. Like the Claude Code plugin, it opens an existing branch's worktree, which OpenCode's remove then removes. Docs (#4489, thanks @rzane for #4488) -
Faster bulk removal: removal hands files to one background deleter per repository, not one
rm -rfeach, and deletes read-only directories it used to leave in.git/wt/trash.wt step pruneno longer stalls when two worktrees share a directory name, as Codex worktrees do. (Breaking: prune runs pre-remove hooks concurrently; hooks writing shared state must coordinate.) (#4516, #4361, #4337) -
wt switch -returns to the worktree it left, including a detached worktree or the second checkout of a branch, andwt remove -targets the same worktree. Pre-switch hooks see the resolved destination, sowt switch origin/featurepassesbranch=feature. (Breaking: from a bare repository's directory, commands given no argument act on the worktree of the branch HEAD names.) (#4497, #4496, #4521) -
Template errors name the variable:
{{ brnch }}reportsundefined variable brnchand suggestsbranch. (Breaking: filters such assanitizereject an undefined input, so{{ upstream | sanitize }}needs a guard ordefaulton a branch with no upstream.) (#4350, #4440) -
Templates use MiniJinja 3 (Breaking): objects and lists render Python-style (
{'port': 3000}) instead of as JSON, so use| tojsonwhere JSON is needed;roundrounds half to even;titlecapitalizes fewer word boundaries (feat/x-ybecomesFeat/x-Y); division by zero errors. ([#4442](https://github.com/max-sixty/worktrunk/p
-
- v0.80.00.80.02026-09-27 · 2026-09-27 21:18 UTC
查看更新说明
Release Notes
Improved
-
wt listand thewt switchpicker settle faster in repos with many worktrees: rows fill from the top down, and on macOS withcore.fsmonitor=trueno daemon start is forked for a worktree whose daemon is already running. On a 50-worktree repo the picker's per-row work starts at 47ms, down from 120ms. (#4286, #4290, #4288, #4284) -
CI status skips branches that were never pushed:
wt list --full, the picker, and the statusline no longer query the forge for a local branch no remote has, so a repo with 239 local branches made 25ghcalls instead of 249. A PR opened from a branch another clone pushed shows once you fetch. GitLab looks up its project ID once per command, not per row. (#4289, #4216) -
Leaner Codex commit generation: the recommended Codex command moves to
gpt-6-lunawith reasoning off and unneeded Codex features disabled, so each message sends fewer input tokens. Accepting the first-run Codex prompt now also creates~/.codex/worktrunk-commit-instructions.txt, which the command reads. Docs (#4261) -
Releases ship a signed packslip: each GitHub release includes
packslip.sigstore.json, a manifest of the archives' digests, platforms, completions, and agent skills, signed by the release workflow so installers such as mise can verify downloads before unpacking. (#4301, thanks @jdx)
Fixed
-
A squash whose commit fails keeps the branch: when a git commit hook or signing stopped the commit in
wt mergeorwt step squash, the branch was left at the merge base with its changes staged, recoverable from the reflog. Now the branch is untouched. (Breaking: git commit hooks run on a detachedHEADduring a squash.) (#4206, thanks @Bennyjitsu for finding it in #4193) -
wt step diffwhen localmainlagsorigin/main: for a branch built on the newerorigin/main, the diff included the upstream commits in between. It now uses the same base aswt merge. (#4281, thanks @starlightromero, whose #3519 reported the same case forwt merge) -
Submodules with an
ignoresetting: whensubmodule.<name>.ignoreordiff.ignoreSubmoduleshid uncommitted changes inside a submodule,wt removeandwt step pruneread the worktree as clean and removed it along with them; they now keep it. Withignore=all,wt step commitand squashes now commit a staged submodule pointer instead of leaving it staged. (#4252, #4192, #4206, #4303, thanks @Duang777) -
Worktrees whose
.gitwas deleted but whose directory remains (macOS$TMPDIRcleanup can do this):wt remove <branch>failed, andwt step pruneskipped or errored on them. Both now unregister the worktree and leave its files; one with staged changes or an operation in progress is kept bywt step prune, and refused bywt removewithout--force. (#4228, #4226, #4302) -
wt merge --no-squashwith a stage mode that stages nothing: with--stage=noneand only unstaged changes
-
- v0.79.00.79.02026-09-21 · 2026-09-21 01:01 UTC
查看更新说明
Release Notes
Improved
-
wt switch --no-cd -x <program>runs the program in the worktree: it started in the invoking directory, so a program meant for the new worktree had to be handed{{ worktree_path }}.--no-cdnow governs only your shell —wt switch feature --no-cd -x code -- .opens the worktree in an editor and leaves your terminal put. (Breaking: a program that wanted the invoking directory needs an explicitcd.) Fixes #4042. (#4179, thanks @yajo for reporting) -
The picker's preview tabs show which have content: a tab's label is dim when that tab is empty for the selected row, and underlined when it's the active tab. Availability sat on the tab's number alone, so every inactive label read dim whatever the row held. (#4174)
-
Messages name the destination, and end with the command to run: without shell integration,
wt mergeandwt removeprintedCannot change directory — shell integration not installedand no path; the warning now names the worktree, aswt switchalready did. "Cannot determine default branch" had three wordings, and three recovery hints put their command first rather than last. (#4163, #4155, thanks @blrain3 for reporting) -
/wt-switch-createno longer stalls at Claude Code's path-entry dialog: Claude Code confirms every entry outside.claude/worktrees/, which is every Worktrunk worktree, so a background session waited for someone to attach. The plugin now approves entry into a worktree at itsworktree-pathlocation, and reads a bare name as the repo or the branch. (#4158, #4159) -
wt config update --outputaccepts the config being migrated: it refused that path when the migration droppedapproved-commands. Those approvals now move to approvals.toml first, exactly as the in-place update moves them. (#4204)
Fixed
-
wt mergeon a dirty worktree describes what it commits: the generated message covered the branch's earlier commits and said nothing about the work the merge had just staged into the same commit.wt step squash --dry-runnow previews what the run would commit, aswt step commit --dry-rundoes. (#4178) -
A config save no longer rewrites the rest of your config: declining a prompt, or setting the commit-generation command, rewrote the whole file, dropping values written at their default and re-spelling hook pipelines and dropping their comments. It also reloaded that file over the in-memory config, so
wt step commit --config-set 'commit.stage="none"'staged everything once it had asked about commit generation. (#4160, #4156, #4151) -
Diff display config no longer reaches Worktrunk's prompts or its integration check:
color.ui = alwaysanddiff.externalreached the commit, squash, and summary prompts. Two corner cases also madewt removeandwt step prunedelete an unmerged branch:diff.relativeset and a Worktrunk command run from a subdirectory the branch's changes sat entirely outside, orsubmodule.<name>.ignore = all(git config or.gitmodules) and a submodule bump as its only change. (#4146, #4147) -
Auto-staging names a wholly untracked directory once: since 0.78.0 the warning expanded each one into its files, so
wt step commit,wt step squash, andwt mergelis
-
- v0.78.00.78.02026-09-16 · 2026-09-16 21:04 UTC
查看更新说明
Release Notes
Improved
-
Hook scripts read renamed context keys: the JSON piped to every hook drops
worktree,repo_root,main_worktree, andmain_worktree_pathin favour ofworktree_path,repo_path,repo, andprimary_worktree_path. Config templates migrate on load, so hooks written with the old names keep working; scripts reading the JSON,--executetemplates, and--varoverrides need updating. (Breaking.) (#4080) -
wt config plugins piinstalls for Pi; oh-my-pi moves towt config plugins omp:pi installwrote an oh-my-pi hook, which Pi never loads; Pi users re-run it to get a Pi extension. Existing oh-my-pi hooks keep working, listed as outdated untilwt config plugins omp install. (Breaking: scripts that runwt config plugins pifor oh-my-pi needomp.) Docs (#4135, thanks @ashebanow) -
Interactive prompts no longer open with a blank line:
wt config shell install,wt config plugins claude install, and the commit-message setup offer inwt mergebegan with one. (#4059) -
wt config showgives a singlewt config shell installhint: an outdated wrapper, a fish wrapper at the deprecatedconf.dpath, and missing fish completions each printed their own hint. The zshcompinitsnippet is now syntax-highlighted. (#4059) -
wt config update --output <path>confirms the write: it now prints✓ Wrote user config migration @ ~/migrated.tomlwhere it printed nothing.--output=-stays silent. (#4053)
Fixed
-
Removal no longer discards untracked files hidden by
status.showUntrackedFiles = no: under that setting, a worktree holding only untracked files looked clean, sowt remove,wt merge, andwt step pruneremoved it without--force. Safety checks now always count untracked files, and auto-staging warnings list every file they stage. (#4111, thanks @Duang777) -
wt removeandwt mergecheck the right worktree under an inheritedGIT_DIR: run from a!wtgit alias or a git hook, which passGIT_DIRdown,wt removecould delete a dirty worktree without--force, andwt mergecould refuse a clean merge. Both now check the worktree they act on. (#4082, thanks @Duang777) -
wt mergeno longer deletes a worktree locked withgit worktree lock: the merge completes and printsWorktree preserved (locked). Every Worktrunk removal refuses a locked worktree, even with--force; rungit worktree unlock <path>first. (#4073, thanks @Duang777) -
wt config updateno longer overwrites a config edited while its prompt is open: it wrote the pre-prompt snapshot over the newer file and reported success. It now fails with the path and leaves the newer file; re-running previews the current contents. (#4127, thanks @zach-hammad-vs for reporting) -
wt step pruneno longer deletes a branch created minutes ago from an older commit:--min-ageaged a branch without a worktree by its commit's date, so a new branch off a day-old commit was pruned on the next run. Age now comes from the branch's oldest reflog entry. (#4077) -
A comment or blank line above an inline config section no longer breaks the config: a save or migration that rewrote
commit = { … }as[commit]put that line inside the brackets.wt switch,wt merge,wt remove, and severalwt stepcommands then failed withFailed to load config;wt listwarned and ran without the config. Saves also d
-
- v0.77.00.77.02026-09-08 · 2026-09-08 22:12 UTC
查看更新说明
Release Notes
Improved
-
wt listsizes and aligns its columns to the terminal width: one long branch name no longer sizes the Branch column for every row — it caps at 32 characters and elides, so a narrow terminal keeps its other columns instead of degenerating into a branch list.Remote⇅stops holding blank space open in a repo with no remote, and alignment now follows the value type.--format=jsonstill carries the whole name. (#3998) -
wt listnames what it hid and marks detached worktrees: the summary readshidden: Path, Commitinstead of counting columns, a detached worktree shows⊘rather than borrowing⚑, and a prunable row leaves its cells blank instead of showing loading dots that never resolve. (#3998) -
wt list --format=jsongains amarkerfield and stops reportingdetachedtwice: the branch marker set bywt config state markeris now readable without parsing it out ofsymbols, andstateno longer reports a detached worktree asbranch_worktree_mismatch— the siblingdetachedboolean carries it. (#3998) -
wt list --format=jsonnow defaults to schema 2: callers get the envelope with repository metadata and orthogonal per-item facts without configuring[list] json-schema.wt list statusline --format=jsonfollows the same key. Setjson-schema = 1to retain the original bare-array format. (Breaking.) (#4038) -
wt config showfails on a broken config: it exits 1 on an unreadable or invalid config, an invalid[list] columns, or an invalidapprovals.toml. Unknown keys and deprecations stay warnings and still exit 0. A newAPPROVALSsection counts project commands awaiting approval. (Breaking: it always exited 0 before.) (#3999) -
Config migration output names its destination:
wt config update --output <path>writes the migration artifact to that file instead of applying it in place, and--output=-writes it to stdout. Output mode includes project config when run from a linked worktree. (Breaking:--printwas removed.) (#4021) -
Pi joins the agent integrations:
wt config plugins pi installwrites an activity hook to~/.omp/agent/hooks/pre/worktrunk.ts, so Pi sessions show 🤖/💬 markers inwt listlike Claude Code, Codex, OpenCode, and Gemini.$PI_CONFIG_DIR,$PI_CODING_AGENT_DIR, and named$OMP_PROFILE/$PI_PROFILEprofiles are honored. Docs (#3594, thanks @adity982, and @ortonomy for the request) -
wt config plugins codex installinstalls the plugin too: it previously registered the marketplace and left you to run/pluginsin Codex yourself. Uninstall follows for both Codex and Claude Code, removing the plugin and then the marketplace, so the two commands are inverses. (Breaking: Codex uninstall previously left an installed plugin alone; Claude uninstall now also removes the marketplace.) (#4019) -
wt step copy-ignoredsays whether it reflinked or copied: the summary now reads(reflinked, no extra disk),(full copy), or a partial count, so the same29.5 GBline distinguishes a free copy from one that actually wrote the bytes.--format=jsongainsreflinkedandwritten. (#4025) -
wt config updateremoves keys its destination cannot hold: migrating[select]or[commit-generation]drops keys the new section has no field for, reporting each one. Otherwise the key landed at a path the user never typed and warned on every command, with no way to clear it. ([#3994](https://github.com/max-si
-
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
November 2026: Worktrunk was released at the start of the year, and has quickly become the most popular git worktree manager. It's built with love (there's no slop!). Please let me know any frictions at all; I'm intensely focused on continuing to make Worktrunk excellent, and the biggest help is folks posting problems they perceive.
Worktrunk is a CLI for git worktree management, designed for running AI agents in parallel.
Worktrunk's three core commands make worktrees as easy as branches. Plus, Worktrunk has a bunch of quality-of-life features to simplify working with many parallel changes, including hooks to automate local workflows & copy-on-write build caches.
A quick demo:

📚 Full documentation at worktrunk.dev 📚
Context: git worktrees
AI agents like Claude Code and Codex can handle longer tasks without supervision, such that it's possible to manage 5-10+ in parallel. Git's native worktree feature gives each agent its own working directory, so they don't step on each other's changes.
But the git worktree UX is clunky. Even a task as small as starting a new
worktree requires typing the branch name three times: git worktree add -b feat ../repo.feat, then cd ../repo.feat.
Worktrunk makes git worktrees as easy as branches
Worktrees are addressed by branch name; paths are computed from a configurable template. Commands that take a branch also accept the path of the worktree it is checked out in.
Core commands:
- Hooks — run commands on create, pre-merge, post-merge, etc
- LLM commit messages — generate commit messages from diffs
- Merge workflow — squash, rebase, merge, clean up in one command
- Interactive picker — browse worktrees with streaming CI status and diff, log, PR and comment previews
- Share build caches — ten worktrees get
target/,node_modules/, etc without building or copying them (on APFS, btrfs, and XFS) wt list --full— CI status and AI-generated summaries per branch- PR checkout —
wt switch pr:123to jump straight to a PR's branch - Dev server per worktree —
hash_porttemplate filter gives each worktree a unique port - Aliases & per-branch variables — custom
wt <name>commands and branch-scoped state for hook templates - ...and lots more
Multiple parallel agents, same simple commands:

Install
Homebrew (macOS & Linux):
brew install worktrunk && wt config shell install
Shell integration allows commands to change directories.
Cargo:
cargo install worktrunk && wt config shell install
Windows. wt defaults to Windows Terminal's command, so Winget additionally installs Worktrunk as git-wt to avoid the conflict:
winget install max-sixty.worktrunk
git-wt config shell install
Alternatively, disable Windows Terminal's alias (Settings → Apps → Advanced app settings → App execution aliases → "Terminal"/"Terminal Preview") to use wt directly.
Free code signing provided by SignPath.io, certificate by SignPath Foundation — policy.
Arch Linux:
sudo pacman -S worktrunk && wt config shell install
Conda / Pixi (community-maintained feedstock):
conda install -c conda-forge worktrunk && wt config shell install
Or with Pixi: pixi global install worktrunk && wt config shell install.
Quick start
Create a worktree for a new feature:
$ wt switch --create feature-auth
✓ Created branch feature-auth from main and worktree @ ~/repo.feature-auth
This creates a new branch and worktree, then switches to it. Do your work, then check all worktrees with wt list:
$ wt list
Branch Status @± ^↕ ^…± Remote⇅ Commit Age Message
@ feature-auth + ↑ +27 -8 ↑1 +31 4bc72dc 2h Add authenticatio…
^ main ^⇡ ⇡1 0e631ad 1d Initial commit
○ Showing 2 worktrees, 1 with changes, 1 ahead, hidden: Path
The @ marks the current worktree. + means staged changes, ↑1 means 1 commit ahead of main, ⇡ means unpushed commits.
When done, either:
PR workflow — commit, push, open a PR, merge via GitHub/GitLab, then clean up:
wt step commit # commit staged changes
gh pr create # or glab mr create
wt remove # after PR is merged
Local merge — squash, rebase onto main, fast-forward merge, clean up:
$ wt merge main
◎ Generating commit message and committing changes... (2 files, +53, no squashing needed)
Add authentication module
✓ Committed changes @ a1b2c3d
◎ Merging 1 commit to main @ a1b2c3d (no rebase needed)
* a1b2c3d Add authentication module
auth.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
lib.rs | 2 ++
2 files changed, 53 insertions(+)
✓ Merged to main (1 commit, 2 files, +53)
◎ Removing feature-auth worktree & branch in background (same commit as main, _)
○ Switched to worktree for main @ ~/repo
For parallel agents, create multiple worktrees and launch an agent in each:
wt switch -x claude -c feature-a -- 'Add user authentication'
wt switch -x claude -c feature-b -- 'Fix the pagination bug'
wt switch -x claude -c feature-c -- 'Write tests for the API'
The -x flag runs a command after switching; arguments after -- are passed to it. Configure post-start hooks to automate setup (install deps, start dev servers).
Next steps
- Learn the core commands:
wt switch,wt list,wt merge,wt remove - Set up hooks for automated setup
- Explore LLM commit messages, interactive picker, Claude Code integration, CI status & PR links
- Browse tips & patterns for recipes: aliases, dev servers, databases, agent handoffs, and more
- Extending Worktrunk — customize workflows with hooks & aliases
- Watch @DevOpsToolbox's video on Worktrunk
- Run
wt --helporwt <command> --helpfor quick CLI reference
Contributing
- ⭐ Star the repo
- Tell a friend about Worktrunk
- Open an issue — feedback, feature requests, even a small friction or imperfect user message, or a worktree pain not yet solved
- Share: X · Reddit · LinkedIn
📚 Full documentation at worktrunk.dev 📚