最近一直在用 AI 编程代理处理日常开发Codex CLI、Claude Code CLI 这类工具确实能顶不少活。但用多了就发现一个很现实的问题当你同时开好几个 Agent让一个去修登录超时、一个去做新接口、一个去翻历史 bug 的时候它们默认都会在当前目录里操作分支切换来切换去临时文件互相覆盖跑测试还会撞端口。更要命的是一个 Agent 把代码改到一半另一个 Agent 的自动提交直接把你还没 review 的改动带走了。我试过强行分成几份克隆仓库但多个克隆各自推分支、各自拉主分支同步成本也很高。后来绕了一圈回到 Git Worktree 这个官方机制上但原生命令用起来还不够顺手于是就有了 Worktrunk一个面向并行 AI Agent 工作流的 Git Worktree 管理 CLI。这个工具解决的是“多个 Agent 同时干活时工作区互相污染”的问题。核心做法是把每个任务放到独立的 worktree 目录里每个目录对应一个清晰命名的工作分支而 Worktrunk 负责帮你把这些目录创建、切换、清理、以及和 Agent 会话绑定起来。适合谁用如果你在用 Codex CLI、Claude Code、Trae CLI 之类的编程助手做多任务并行或者你平时就习惯同时维护多个 feature 分支这篇文章应该能帮上忙。下面我从设计思路到实际踩坑一步步讲清楚。1. 为什么并行 AI Agent 工作流需要 Worktrunk1.1 多 Agent 并行的分支地狱先说痛点。假设你只有一个仓库当前在 main 分支上你开了三个终端窗口分别让三个 AI Agent 干活。它们共享同一份工作目录git status 看到的是同一堆改动。Agent A 说“我改完了帮你跑一下测试”Agent B 却正在改测试文件结果 A 的测试结果根本不可信。Agent C 更直接它发现当前分支是 main觉得可以直接 commit于是一不小心就把 A 和 B 还没写完的东西全部提交到一个看起来很干净的历史里。这种问题其实和人协作时一样多个任务在同一个工作区里叠加彼此干扰。人还知道互相打个招呼AI Agent 可不会管你。所以最直觉的解法是一人一个目录互不干扰。这就是 Git worktree 的用途。它允许你从同一个仓库里拉出多个工作目录每个目录 check out 不同的分支共享同一个 .git 对象库。这样改动天然隔离推拉代码又不需要重新 clone 一份全量历史。1.2 Git Worktree 是怎么解决问题的Git worktree 的基本用法其实很简单。在一个仓库里执行git worktree add ../login-fix hotfix/login-timeout就会在当前仓库的父目录下生成一个 login-fix 文件夹里面是 hotfix/login-timeout 分支的一个独立 checkout。你可以在这个目录里随意改代码、提交、推送不影响主目录里正在做的其他事情。底层的原理是每个 worktree 都有自己独立的工作区、index、HEAD但共用仓库的 .git 目录。你用git worktree list可以看到所有关联的工作目录。原生命令虽然能解决问题但用起来有几个烦人的地方一是路径和分支全靠你手动起名字起多了容易乱二是删除的时候要先删分支再删目录顺序反了就会报 “branch is checked out at another location”三是没有任何任务维度的概念你很难一眼看出哪个 worktree 对应哪个 Agent 任务。1.3 Worktrunk 的定位给 worktree 加一层工作流编排Worktrunk 不是要替换 Git而是在 Git worktree 之上做的一层薄封装专门给“并行 AI Agent 任务”服务。它的核心思路是把每个 Agent 任务当成一个独立工作区命名规范、分支映射、目录创建、清理校验都由工具自动完成。从定位上看它可以理解成一个“任务即目录”的管理器。你不需要记住 worktree 的完整语法只需要说我要为“修登录超时”这个任务开一个工作区用 Codex 去跑。Worktrunk 就会自动创建目录、建立分支、记录下来并在你启动 Agent 时把工作目录切过去。这样多个 Agent 并行时天然有了边界不会互相踩脚。2. 核心细节解析Worktrunk 的关键设计2.1 工作区生命周期管理Worktrunk 把 worktree 抽象成几个简单的命令。最核心的是create、list、remove、prune。每个命令背后都对应到对 git worktree 的操作但会帮你处理很多边界情况。创建时命令大概长这样worktrunk create login-timeout-fix --base main --agent codex它会做几件事根据任务 slug 生成一个规范化的分支名比如worktrunk/login-timeout-fix在约定目录默认workspaces/login-timeout-fix下创建 worktree并把这个工作区关联到一个 Agent 类型上。这个关联信息会写进仓库下的.worktrunk/config.json下次你运行 AI Agent 时可以直接调用。列出时worktrunk list会展示所有工作区的名字、分支、目录路径、当前是否有未提交改动以及绑定的是哪个 Agent CLI。这样你在开多个窗口的时候一眼就知道哪个任务对应哪个目录。删除时worktrunk remove会先检查这个工作区里有没有未提交的改动。有的话会提示你是要保留、强制删除还是先 stash 起来。确认之后它会切回主分支、删除 worktree再清理掉对应的远程分支引用。这个步骤如果你手动用 git 做非常容易漏掉“删除分支前需要先移除 worktree”这一步。2.2 分支命名和映射策略分支命名是 Worktrunk 让我觉得最省心的地方。原生的git worktree add允许你给目录一个名字也给分支一个名字但两者之间没有强关联。时间一长你看到workspace-2024-03-fix2这种目录根本想不起来这是干嘛的。Worktrunk 采用worktrunk/slug的分支命名slug 来源于你传入的任务名。比如任务名是 “fix login timeout”它会生成worktrunk/login-timeout-fix。这个命名策略有几个好处一是一眼能看出是 Worktrunk 管理的分支二是 slug 从任务名自动生成不会出现两个人起同样的名字导致冲突三是方便批量清理比如过期分支可以直接用git branch --list worktrunk/*列出来再删。如果你希望分支不挂在worktrunk/下面也可以在配置里改成自己的前缀。这个看起来很简单的设计实际上是整个工具能不能长期用下去的关键。因为并行 Agent 工作流一旦多起来命名不规律的话后续维护成本比任务本身还高。2.3 Agent 上下文绑定Worktrunk 不只是把目录建好就完事它还把“Agent 应该在哪里跑”这个上下文也管了起来。你可以给每个任务指定用哪个 AI 编程代理。比如创建时指定--agent codex之后运行worktrunk run login-timeout-fix -- codex它就会先检查这个任务的 worktree 是否存在然后把当前工作目录切到对应目录再执行后面的命令。这样做有什么意义因为很多 AI Agent 会记住当前目录下的文件状态、项目配置、甚至 git 历史。如果你在错误的目录里启动 Agent它会读到完全不同的上下文然后给出牛头不对马嘴的建议。通过 Worktrunk 统一入口可以保证“在哪个工作区干活就在哪个工作区里启动 Agent”。这不是一个复杂的机制但很实用。我自己的习惯是每次创建一个新任务就让 Worktrunk 把目录绑定到终端 Tab 的名字上这样窗口标题就显示了任务名不容易开错。2.4 资源隔离和 GC 清理AI Agent 跑任务的过程中会产生不少临时文件、日志、依赖缓存。一个 worktree 是一个独立目录但这并不意味着所有东西都会隔离。比如 node_modules 如果你放在仓库根目录并提交到了 .gitignore那么每个 worktree 都需要重新装一次依赖如果依赖目录在仓库外共享那又会互相影响。Worktrunk 提供了一个sync命令可以把主工作区里的依赖目录比如 node_modules、vendor、.venv通过硬链接或复制的方式快速同步到新的 worktree而不是让每个 Agent 在创建任务后重新跑一次完整安装。同时它也有一个prune子命令用来清理那些已经很久没活动的工作区。这个命令会列出每个 worktree 的最后提交时间和正在跑的任务。你可以设置超过多少天没动过的就标记为过期然后一键清除。这里要说明一点prune的默认行为不会删除有未提交改动的目录。你要是用--force强行清理丢掉的东西不会进回收站。所以我个人建议日常清理时先接上远程分支推送确保工作成果有备份再执行删除。3. 实操过程从安装到两个 Agent 并行跑起来3.1 安装与环境检查Worktrunk 目前通过 Go 写的单文件二进制安装很简单。如果你本地有 Go 环境可以直接go install github.com/worktrunk/worktrunklatest或者下载对应平台的 release 包放到 PATH 里就行。安装完先检查一下 git 版本worktree 需要 Git 2.7 以上才支持2.17 以上才比较稳定。git --version worktrunk version然后是初始化。进入你现有的仓库执行worktrunk init它会创建一个.worktrunk/目录里面放了默认配置。包括工作区根目录用workspaces/分支前缀用worktrunk/以及默认 Agent 类型。这些配置都写在.worktrunk/config.json里你可以手动改。init 之后 Worktrunk 不会擅自改动你当前的 git 状态所以可以放心跑。3.2 创建和管理并行工作区现在假设我要同时做两个任务一个是修复登录超时另一个是给列表接口加缓存。分别执行worktrunk create login-timeout-fix --base main --agent codex worktrunk create list-cache --base main --agent claude执行完以后项目根目录下会多出workspaces/login-timeout-fix和workspaces/list-cache两个文件夹。每个文件夹都是一个独立分支的完整 checkout。用worktrunk list看一下Name Branch Dir Agent Status login-timeout-fix worktrunk/login-timeout-fix workspaces/login-timeout-fix codex clean list-cache worktrunk/list-cache workspaces/list-cache claude clean这样两个 Agent 就可以分别在两个目录里干活了。打开两个终端分别执行cd workspaces/login-timeout-fix codex另一个终端cd workspaces/list-cache claude它们各自的代码变更、git 提交、测试运行都在自己的 worktree 里互不干扰。实际跑下来我能明显感觉到 AI Agent 的“精神分裂”情况少了很多。之前让同一个 Agent 连续跑两个不同需求它经常把上一个需求的改动带到下一个里面去现在每个需求一个干净分支Agent 的上下文从环境层面就被隔离了。3.3 让 Agent 自动进入对应工作区如果你不想每次手动 cdWorktrunk 支持一个运行器worktrunk run login-timeout-fix -- codex这个命令会切到workspaces/login-timeout-fix目录然后执行codex。好处是它把目录切换和 Agent 启动绑定在了一起。你还可以把这个命令封装成 shell 函数比如function wcodex() { worktrunk run $1 -- codex }之后每次开新终端只要wcodex login-timeout-fix就自动进入对应工作区并启动 Codex CLI。用这种方式管理多个并行任务效率比我之前手动建目录高非常多。尤其当你同时开着五六个任务终端窗口多到记不清谁是谁的时候这套机制的价值就完全体现出来了。3.4 配合 CI 和定时清理任务收尾时我先在 worktree 里跑完测试然后推送分支接着用 Worktrunk 清理worktrunk push login-timeout-fix worktrunk remove login-timeout-fixpush会帮你把当前分支推送到远程并设置好 upstream。remove则负责清理本地 worktree 和分支。如果你不想用完就删也可以保留等远程 PR 合并后再统一清理。定时清理的话可以写一个简单的 cron 任务0 2 * * * cd /path/to/repo worktrunk prune --older-than 14d --force这里要小心--older-than 14d是看最后提交时间而不是创建时间。一个分支虽然创建很久但一直有提交就不会被误删。这个设计对有长期维护的分支比较友好。4. 常见问题与排查技巧实录4.1 分支删不掉worktree 还挂着这是新手最容易踩的坑。你用git branch -D feature/xxx删分支结果 Git 提示error: cannot delete branch ... checked out at ...。为什么会这样因为 Git 不允许删除一个正在被 worktree checkout 的分支。解决办法是先看有哪些 worktreegit worktree list如果确认那个目录已经没用了先把对应的 worktree 删掉git worktree remove /path/to/workspace然后再删分支。用 Worktrunk 的话直接worktrunk remove task就可以了。它会先删 worktree再删分支顺序正确。如果 worktree 目录被手动移动过可能还需要git worktree prune清理一遍失效记录。4.2 worktree 里的 .git 文件指向了错的目录普通仓库里worktree 目录下没有.git文件夹而是一个.git文件里面写着指向主仓库.git/worktrees/目录名的路径。如果你用 IDE 或脚本把整个 worktree 目录移动到了别的位置这个.git文件里的相对路径可能就失效了。这时 Git 会认为这个目录不是仓库的一部分无法操作。解决办法有两种。一是尽量别移动 worktree 目录如果非要移动用git worktree repair来修复。另一种就是在 Worktrunk 的设计里从一开始就让 worktree 目录保持在仓库目录下减少手动搬移的冲动。我后来遇到这类问题基本都是因为想“把 workspace 放到别的磁盘”结果路径一偏就崩。4.3 Agent 生成的变更互相覆盖有人问过我我都用 Worktrunk 建了不同的 worktree为什么两个 Agent 的改动还是会互相覆盖仔细查了一下发现是配置文件的问题。项目根目录可能有一些环境配置比如.env、local.properties这些文件如果被.gitignore排除就不会出现在每个 worktree 里。结果 Agent 都在各自的 worktree 里生成了新的本地配置这些配置的路径又指向同一个全局位置比如用户主目录于是产生了“看似在工作区里其实在外部共享”的状态。这种情况严格来说不是 worktree 的问题而是共享配置导致的问题。排查技巧就是看 Agent 到底改了哪些文件不要只看当前目录。如果所有 worktree 都指向同一个~/xxx缓存那并行度再高也没用。建议把 Agent 的缓存目录、配置文件都设置成跟随当前工作区或者在每个 worktree 里单独初始化一份本地配置。4.4 一些避坑经验总结我把实际使用中比较值得注意的点整理成一张表方便你快速对照。问题可能原因解决建议git worktree list里目录已不存在手动挪走或删除目录先移动目录时用git worktree repair再执行prune删除 worktree 时提示有未提交改动目录里有 .gitignore 之外的新文件确认改动后 commit 或 stash再用git worktree remove --force不同 worktree 里依赖版本不一致每次重新安装依赖产生版本漂移用worktrunk sync从主工作区同步依赖快照Agent 看到别的任务的临时文件worktree 目录共享了外部临时目录给 Agent 设置独立临时目录或把TMPDIR改成 worktree 内路径远程分支推不上去本地分支落后或强制推送策略限制worktrunk push前先检查是否基于最新 base必要时 rebase另外一个很实际的经验是尽量保持同一个项目只在一个 Worktrunk 工作区里跑长期任务临时任务用完就删。因为每次create都会基于 base 分支拉一个新分支如果 base 分支长期不更新那么你建的每个新任务都会基于一个旧基线开始之后 merge 回来的时候冲突会很恐怖。所以我每周都会先切回主分支拉一遍最新代码再继续开新任务。4.5 关于 Agent 工作流隔离的补充思考Worktrunk 解决的是目录和分支隔离但它不解决 Agent 自身的状态记忆问题。比如 Codex CLI 可能会把对话历史存在主目录的某个地方这样两个不同的 worktree 里跑同一个 Agent它还是可能记得上一个任务的内容。如果你希望每个任务有完全独立的 Agent 会话记忆还需要把 Agent 的配置目录也按任务隔离。常见做法是设定环境变量比如CODEX_HOME或CLAUDE_CONFIG_DIR跟随 worktree。Worktrunk 在创建任务时会生成一个.worktrunk/env.sh文件里面可以放一些每个任务独立的环境变量。比如export CODEX_HOME$PWD/.codex_home export TMPDIR$PWD/.tmp然后在worktrunk run的时候自动 source 这个文件。这个设计很轻但效果很明显。我试过把几个任务的会话配置完全分开之后Agent 之间的“串戏”情况基本消失了每个任务从头到尾都能保持它自己的上下文代码生成质量稳定了不少。5. 一点个人体会工具要配流程才有效5.1 和 Git 原生命令共存Worktrunk 并没有屏蔽原生的 git 命令。你在 worktree 里依旧可以用git status、git add、git commit、git push等等唯一的区别是 Worktrunk 帮你约束了目录和分支的命名、创建和清理流程。这样做的好处是即使有一天你不想要 Worktrunk 了这些 worktree 都是标准的 Git 概念你可以随时用git worktree remove手动清理干净没有绑定成本。从工具设计的角度来说这是我很欣赏的一点它没有发明一套新的版本控制概念只是把标准机制包装得更好用。玩过很多开发工具我认为真正能留下来的小工具往往是这种“轻封装、顺应标准工具”的类型而不是彻底另起炉灶。5.2 后续还可以怎么扩展Worktrunk 目前只是管住了本地工作区但我觉得它完全可以继续往前走。比如每个任务自动生成一个对应的远程分支创建 Pull Request 之后直接把链接贴在任务列表里或者把多个任务的最终改动合并成一个汇总分支方便最后统一验证还可以接入通知当一个任务跑完测试后推送到消息平台。其实很多团队已经在用脚本做类似的事情Worktrunk 只是把这些常见需求固定成了命令。如果你也想自己折腾可以用 shell 脚本写一个最小版本核心就三件事git worktree add、git worktree list、git worktree remove再加上一个任务名到目录的映射文件。很多工作流只要有一层简单的封装体验就会完全不同。最后再分享一个我自己用的时候的小技巧为每个 Worktrunk 工作区设置一个不同的终端底色或标题。我用终端的 title 显示任务名配合worktrunk run自动切换一眼就能看出当前终端在跑哪个任务。这个习惯让多任务并行的体验又上了一个台阶强烈推荐试试。
