Worktrunk:用Git Worktree管理并行AI Agent工作流
2026/9/20 19:50:39 网站建设 项目流程

最近一段时间我一直在折腾并行 AI Agent 编程。手头一个大仓库,想让 Claude Code 和 Codex CLI 同时干活:一个改登录鉴权,一个做接口缓存,另一个去优化前端构建脚本。理论上很美好,实际一把梭下来全是坑——同一份工作目录里,两个 Agent 会互相覆盖改动,A 刚把依赖升级,B 这边测试就挂了,更别提谁动一下根目录配置,另一个人直接崩盘。后来我把目光转向了 Git Worktree,一开始还觉得它是个老古董功能,用上手才发现,这玩意儿简直是给 AI 编程时代准备的。今天要聊的 Worktrunk,就是我围绕 Git Worktree 写的一个管理 CLI,专门用来调度并行 AI Agent 工作流。

不管你是用 Codex CLI、Claude Code、Trae CLI,还是自己写基于 Agent 的自动化脚本,只要你有"同一个仓库多任务并发改代码"的需求,这篇文章都值得看完。我会把工具的设计思路、安装使用、实际跑通的三路并行案例,以及我踩过的那些坑全部摊开讲。内容比较实操,建议你打开终端边看边试。

1. 为什么 AI Agent 写代码时,目录会变成单行道

先说结论:绝大多数 AI 编程工具本质上就是一个"能自主读文件、改文件、跑命令的进程",它们消灭了键盘输入的人工成本,却没有消灭文件系统层面的冲突。你让两个 Agent 在同一个工作目录里同时改代码,就像把两个人塞进同一间办公室共用一张桌子,不是不能干活,是效率极低。

1.1 单目录并行的三个痛点

痛点一是文件互踩。Agent A 正在读api/client.ts,准备加上重试逻辑,Agent B 拿到同一份文件,把超时时间从 3000 改成 5000,保存。A 这边再写的时候,基于的内存快照已经过期,一提交就把 B 的逻辑覆盖了。这种情况在真实协作里几乎无解,因为两个 Agent 之间没有天然的"文件锁",你也不可能给每个 AI 工具都加上"别人正在编辑,请等一等"的通知机制。

痛点二是依赖和构建产物互相污染。同一个node_modules、同一个target、同一个dist目录,两个 Agent 同时在装依赖、跑测试,结果就是共享缓存被写乱,编译报错还会互相甩锅。我在第一次实验里就遇到过:Agent A 把lodash从 4.x 升到 5.x,Agent B 那边的单测立刻全红,但它自己完全没动过依赖。

痛点三是 Agent 会话的上下文污染。并行任务一旦共用一个工作区,Agent 读取README、读AGENTS.md、扫全仓库文件时,看到的改动可能是另一个任务写了一半的状态。这种情况下,即使文件内容没有崩溃,Agent 也会产生错误判断,把别人没写完的代码当成既有逻辑去推导,产出的方案经常驴唇不对马嘴。

1.2 Git Worktree 为什么是对的方向

Git Worktree 是 Git 2.5 引入的功能,允许你在同一个仓库上创建多个工作目录,每个目录可以检出不同的分支。原理上,多个 worktree 共享同一个.git对象数据库,但拥有各自的HEAD、索引文件和工作区文件。也就是说,你在worktree-A里提交的分支对象,在worktree-Bgit log也能看到,但两边改的文件互不干扰。

这个特性对并行 AI Agent 工作流来说几乎是量身定做:每个 Agent 住进一个独立的"房间",房间里有自己完整的代码副本和分支,可以随便改、随便测、随便提交,不会碰到其他 Agent 的桌子。等到任务完成,再把分支合回主干。Git 的对象数据库共享机制还保证了集成时历史是连贯的,不会出现"两套独立仓库最后对不上"的问题。

但 Git 原生的 worktree 命令有几个现实局限。第一,它只管创建目录和分支,不管任务映射,时间一长你根本记不住.worktrees/whatever对应的是哪个需求。第二,它没有清理策略,合并完分支之后 worktree 一个个堆在那里,磁盘白白浪费。第三,也是最重要的一点,它没有为 AI Agent 场景做任何优化,不会自动生成任务上下文、不会帮你规划并行启动流程、也不提供"在指定 worktree 里跑 Agent"的快捷方式。

1.3 Worktrunk 的定位:补齐 Worktree 的最后一公里

Worktrunk 的定位很简单,它是一个夹在 Git 和 AI Agent 之间的管理中间层。解决的问题是:从你拿到一个需求到 Agent 真正开始写代码之间那一大段"杂事"——建分支、建目录、写任务说明、规划并行方式、最后合并清理。

具体来说,Worktrunk 做三件事:把"任务名、分支名、worktree 路径"做成一个稳定映射;为每个任务生成一份标准化的上下文文件,让 AI Agent 一进目录就知道自己要干什么;提供一套精简的命令集,把git worktree addgit mergegit branch -D这些底层操作封装成"对任务进行操作"的高层指令。

如果你只是偶尔开一两个 worktree,手动敲 Git 命令完全够用。但如果你打算同时开五六个 Agent,让它们像一个小团队一样并行推进需求,没有一个统一调度入口,很快会失控。Worktrunk 就是为了这个场景写的。

2. 核心设计:从任务到目录再到合并的一整套映射

设计这个工具时,我最优先想清楚的是一件事:任务生命周期和 Git 对象的对应关系。一个任务从创建到合并,要经过"编号-分支-目录-上下文-状态-合并-清理"这么一长串环节,每一环都要有明确的命名规则和存储位置,否则工具本身就会变成新的混乱源。

2.1 任务与分支的命名规范

我先定了一套非常严格的命名规则。任务名一律小写,单词之间用连字符分隔,例如fix-login-timeoutadd-api-cache。分支名按照wt/{taskId}的格式生成,例如wt/fix-login-timeout。worktree 路径则统一放在仓库根目录下的.worktrees/{taskId}/目录中。

这套规则解决了三个问题:第一,可追溯性——看到分支名或目录名,你能立刻知道这是哪个任务;第二,可清理性——所有 worktree 都在一个固定前缀目录里,worktrunk prune可以安全遍历;第三,可排序性——wt/前缀让这些任务分支在git branch列表里聚在一起,不会和手工分支混成一团。

创建任务的命令长这样:

worktrunk add --name fix-login-timeout --desc "解决登录接口偶发超时" --base main

这条命令背后做了一系列操作:在.gitignore中追加.worktrees/、执行git worktree add .worktrees/fix-login-timeout -b wt/fix-login-timeout main、在该目录下写入AGENTS.md任务上下文、最后在.wt/manifest.json里登记一条任务记录。你不需要关心底层细节,它全帮你搞定。

2.2 状态清单与任务上下文

Worktrunk 的调度核心是一份 JSON 清单文件,默认放在仓库根目录的.wt/manifest.json里。每个任务在清单中占一条记录,包含任务名、描述、分支名、路径、基于分支、创建时间、状态、以及最后负责的 Agent 工具名。

{ "taskId": "fix-login-timeout", "description": "修复登录接口偶发超时问题", "branch": "wt/fix-login-timeout", "path": ".worktrees/fix-login-timeout/", "base": "main", "createdAt": "2025-06-10T10:00:00Z", "status": "in-progress", "agent": "codex" }

状态字段目前支持pendingin-progressreadymergedaborted五种。worktrunk list会读取这份清单并渲染成表格,你可以一眼看出哪个任务在跑、哪个合并完了、哪个被废弃了。

任务上下文文件是另一个关键设计。Worktrunk 会在每个 worktree 里生成一份AGENTS.md,内容直接照抄当前任务的目标、影响范围和验收标准。AI 编程工具基本都支持自动读取这类文件,Agent 一进入工作目录就能拿到"我是谁、我要干什么、我不能碰什么"的完整说明,不需要你在对话里反复粘贴需求,也不会出现两个 Agent 互相改错领域的情况。

2.3 CLI 命令集

Worktrunk 的命令集刻意保持精简,核心命令一共九条,覆盖任务从生到死的全部环节。

命令作用示例
worktrunk init初始化仓库,创建.wt目录结构worktrunk init --remote origin
worktrunk add为任务创建 worktree 和分支worktrunk add -n fix-login-timeout -b main
worktrunk list查看所有任务状态worktrunk list --status in-progress
worktrunk switch在 worktree 间切换目录worktrunk switch fix-login-timeout
worktrunk exec在指定 worktree 中执行任意命令worktrunk exec fix-login-timeout -- "pnpm test"
worktrunk sync将基线分支最新代码同步到各 worktreeworktrunk sync --all
worktrunk merge将任务分支合并回基线并删除分支worktrunk merge fix-login-timeout --base main
worktrunk prune清理已合并或废弃的 worktreeworktrunk prune --merged
worktrunk import接管手动创建的 worktree 目录worktrunk import --path .worktrees/legacy-a

这里我要特别解释一下worktrunk exec的设计。它的本质是在指定 worktree 路径下启动一个子进程,把命令原样透传给 shell。但它在透传之前会先检查该 worktree 是否存在、状态是否正常、目录是否可写,并且在命令执行期间锁定任务的status,防止另一个终端同时对该任务做 merge 或 prune。这个细节在手动使用 Git worktree 时容易被忽略,但一旦并行任务多起来,"你正在跑测试,另一个终端把 worktree 删了"这种事故是真实会发生的。

3. 快速上手:十分钟搭起第一套并行 Agent 流水线

我假设你已经有一台装了 Node.js 16+ 的电脑,并且本机有 Git 2.30 以上的版本。Worktrunk 目前通过 npm 包分发,安装命令:

npm install -g worktrunk

安装完成后,进入你的项目仓库,先初始化。Worktrunk 会检查当前目录是不是一个合法 Git 仓库,并在根目录创建.wt/.worktrees/两个目录。注意,.worktrees/会自动写入.gitignore,因为你绝对不希望 worktree 里的代码副本被当成普通源码提交。

cd ~/projects/monolith worktrunk init --remote origin

首次运行会看到一条提示,告诉你默认忽略规则已写入.gitignore,同时确认当前基线分支为mainmaster。如果仓库有多个长期分支,你可以在后续 add 时通过--base单独指定。

3.1 一个任务对应一个工作区

接下来我们一口气创建三个任务,模拟真实的"三路并行"场景。假设我手上的需求是:修复登录接口超时、给查询接口加缓存、优化前端构建脚本。三条命令如下:

worktrunk add --name fix-login-timeout --desc "修复登录接口偶发超时" --base main worktrunk add --name add-api-cache --desc "给查询接口添加Redis缓存" --base main worktrunk add --name optimize-build --desc "把前端构建改为并行任务" --base main

每执行一条,终端都会输出新 worktree 的路径、分支名和生成的AGENTS.md路径。三秒左右,你的磁盘上就多出了三份独立的代码副本。用worktrunk list看一下整体状态:

worktrunk list

输出会是一张表格,列名分别是任务名、分支、状态、路径、Agent。此刻三个任务都是pending,路径分别是.worktrees/fix-login-timeout/.worktrees/add-api-cache/.worktrees/optimize-build/

3.2 并行执行:怎么让多个 Agent 一起开工

任务创建完之后,并行启动的关键一步来了。我先给每个 worktree 预装一次依赖,这一步强烈建议在 Agent 干活之前做,否则多个 Agent 同时跑包管理器会互相抢锁:

worktrunk exec fix-login-timeout -- "pnpm install" worktrunk exec add-api-cache -- "pnpm install" worktrunk exec optimize-build -- "pnpm install"

依赖装完后,就可以分别启动 Agent。以 Codex CLI 和 Claude Code 为例,实际命令以你本机安装的工具为准:

worktrunk exec fix-login-timeout -- "codex exec '修复登录接口超时问题,验收标准见 AGENTS.md'" worktrunk exec add-api-cache -- "claude -p '给查询接口添加Redis缓存,改动范围限定在service层'" worktrunk exec optimize-build -- "codex exec '把前端构建改为并行任务,参考 AGENTS.md'"

三个进程同时跑在三份独立目录里,互相看不见对方的改动,也就不会产生文件覆盖和上下文污染。你可以打开三个终端窗口,分别观察每个 Agent 的执行日志。这时候worktrunk list会显示任务状态逐渐变成in-progress,非常直观。

3.3 查看状态、提交与切换

并行运行期间,我习惯用worktrunk list来当仪表盘。如果某个任务已经完成,Agent 会在 worktree 里做好提交,此时你可以进目录人工检查产物,或者直接跑一遍测试:

worktrunk exec fix-login-timeout -- "pnpm test"

如果测试通过,就进入集成环节。worktrunk switch fix-login-timeout会在当前终端里切换目录——这个命令的实现有点小心思,因为实际切换目录必须由当前 shell 来执行,Worktrunk 的 switch 子命令本质上会输出一行cd /absolute/path/to/worktree让你复制执行,或者你直接cd .worktrees/fix-login-timeout一回事。我更喜欢直接用worktrunk exec,因为它不改变终端状态,尤其是跑 Agent 这种长任务时,切换目录反而容易把后续命令发错位置。

4. 并行工作流实战:三路 Agent 并发改同一个仓库

理论说完了,下面我用一个真实跑通过的项目来演示完整流程。这个项目是一个典型的 Web 后端加前端工程,代码量中等,涉及 auth 模块、service 层和构建配置。我把三个任务拆给三个 Agent,目标是同一个小时内全部合并回主干。

4.1 任务拆解与依赖识别

任务拆解是决定并行成败的关键环节。我的判断标准很简单:两个任务之间不能有"同一个文件的修改交集",否则无论 worktree 怎么隔离,合并时还是会冲突。

  • 任务 Afix-login-timeout:改动范围在src/auth/src/api/handler/auth.go,目标是修复登录接口偶发超时。
  • 任务 Badd-api-cache:改动范围在src/service/query.gosrc/cache/redis.go,目标是给查询接口加 Redis 缓存。
  • 任务 Coptimize-build:改动范围在webpack.config.js.github/workflows/build.yml,目标是构建脚本并行化。

三个任务在文件层面没有直接交集,但它们有一个隐藏依赖:都依赖package.json的依赖列表。如果 Agent A 顺手升级了某个包,Agent B 的测试就会受影响。解决办法是在拆解阶段就定死"依赖锁定"规则——谁都不许改package.json里的版本号,需要新依赖就单独提任务。我把这条规则写进每个AGENTS.md的约束栏里。

4.2 并行运行记录

创建好三个 worktree 并预装依赖后,我同时启动了三个 Agent 终端。大约运行到第 12 分钟时,worktrunk list显示add-api-cache已经把状态推成ready,Agent B 在日志里报告"缓存已加上,单测通过"。又过了 5 分钟,fix-login-timeout也进入ready,但 Agent A 提示登录接口的单元测试在本地跑通了,集成测试没有跑,因为集成测试需要启动数据库容器。

optimize-build用时最长,因为它要同时改 webpack 配置和 CI 文件,Agent C 中途主动检查了两次构建产物,确认输出正常后才提交。这里我观察到一个小规律:给 Agent 的验收标准越具体,它自己主动做验证的次数就越多。这个在AGENTS.md里写清楚验收标准,比在对话里反复要求"你要测试哦"有效得多。

4.3 集成合并与冲突处理

三个任务都进入ready后,我开始逐个集成。Worktrunk 的合并策略是先预检再合入,避免直接把冲突炸到主干上:

worktrunk merge add-api-cache --base main --check-first

--check-first参数会先用git merge-tree在后台模拟一次合并,输出可能冲突的文件列表,但不会真正改动工作区。如果检测到冲突,终端会列出冲突文件和涉及的两个分支,并建议你先人工查看。如果没检测到冲突,它会真正执行git merge,把任务分支合并到main,然后询问是否立即清理该 worktree。

三个任务里,add-api-cacheoptimize-build都是零冲突直接合入。fix-login-timeout出现了意外——它虽然没改package.json,但src/api/handler/auth.gosrc/api/handler/query.go在文件头部有一段公共的import区,任务 B 在缓存改造时新增了一个依赖导入,导致两个任务的变更在同一行上产生了冲突。

这种"我没有碰这个文件,但文件头被改了"的情况在并行开发里很常见。解决办法也简单:先开一个终端人工处理冲突,只保留两个任务的变更集合,然后worktrunk merge继续执行。整个集成过程大概花了十分钟,比单 Agent 串行做完三个任务至少省了一半时间。

5. 常见问题与排查技巧实录

工具用得越深,踩的坑越有参考价值。我按实际频率排了个序,把 Worktrunk 使用中容易遇到的问题整理成了下面的速查表。

问题现象可能原因解决办法
worktrunk add报分支已存在之前创建过同名任务,或手工建过同名分支git branch -D wt/xxx删除旧分支,或改用worktrunk import接管
worktrunk list不显示某个 worktree用原生git worktree add手动创建的目录,没登记进 manifest执行worktrunk import --path .worktrees/xxx
多个 worktree 下依赖安装重复工作区独立,node_modules不会共享用 pnpm workspace 配合 symlink,或接受首次安装成本
Agent 改了根目录公共配置AGENTS.md没写清约束AGENTS.md增加"禁止改动"清单,必要时用文件权限隔离
worktrunk prune删除失败目标目录下有进程占用(Agent 或 shell 未退出)先退出该 worktree 下所有进程,再重试
worktrunk sync中断某个 worktree 有未提交的本地改动先执行worktrunk exec 任务名 -- "git add -A && git commit"
合并时检测到不相关文件冲突两个任务同时改了公共文件头部或 import 区人工合并冲突,只保留合理变更集,不要无脑--ours
磁盘空间快速膨胀worktree 共享对象库但工作区独立,构建产物也独立定期worktrunk prune --merged,并把构建产物目录加入.gitignore

5.1 最容易踩的坑:依赖安装和构建产物

我最早踩的坑是并行跑pnpm install。三个 worktree 同时安装依赖,pnpm-lock.yaml互相对不上,最后两个 Agent 的测试全挂了。后来我改成"先在所有 worktree 里预装依赖,再启动 Agent,并且严格禁止 Agent 修改依赖版本",这条规则至今没再出过问题。

构建产物的坑更隐蔽。.worktrees/目录最初放在仓库根目录下,结果某个前端项目的 webpack 配置把整个根目录当成了内容目录,构建时把其他 worktree 的源码也一并打包进去了。我当时的修复方案是两层:第一层把.worktrees/路径加进.gitignore和构建工具的排除列表;第二层调整项目结构,把.worktrees/放到仓库外部。Worktrunk 目前默认生成时自动在.gitignore里追加忽略规则,但如果你的项目构建工具不看.gitignore,还是要自己处理。

5.2 一个值得长期保留的技巧:AGENTS.md 的写法

任务上下文文件写得好不好,直接影响 Agent 产出的质量。我的模板固定包含五个部分:任务描述、影响范围、验收标准、约束条件、参考资料。影响范围写得越具体,Agent 越不会越界乱改;约束条件越明确,越少出现"把整个项目格式化一遍"这种低级事故。

我见过很多同学在AGENTS.md里只写一句"修复登录超时问题",结果 Agent 进来之后不知道改哪个文件,也不知道怎么算完成,最后照着错误路径写了一堆无用代码。任务上下文本质上就是给 Agent 的"产品需求文档",你给它信息越充分,它回来的结果越可靠。

6. 与 AI Agent 工具链的深度配合

Worktrunk 本身不绑定任何具体 Agent 工具,它只提供一个独立目录和一份任务上下文,剩下的事情由你手头的 Codex CLI、Claude Code、Trae CLI 或者自研 Agent 脚本来完成。这个设计是刻意的——AI 编程工具迭代太快,绑定任何一家都有风险。

6.1 和主流 CLI 工具的对接方式

以 Codex CLI 为例,它的执行模式基本是"在当前目录里接受指令并开始自主编码"。Worktrunk 的做法是先把你送进目标 worktree,再启动 Codex,让它认为自己在独立仓库里干活:

worktrunk exec fix-login-timeout -- "codex exec '修复登录接口超时,验收标准见 AGENTS.md'"

Claude Code 的调用逻辑也类似,但它的会话恢复能力更强。你可以在同一个 worktree 里反复启动 Claude Code,让它读取上一次的对话记录继续干活。这种情况下,Worktrunk 的价值在于你不用担心"这个会话对应哪个目录"——任务和目录的映射是确定的,你只要把worktrunk exec的命令交给自动化调度平台就行。

6.2 在自动化流程里用 Worktrunk 做任务分发

如果你想做更复杂的任务编排,比如接一个 Webhook 进来,自动把需求拆成任务并按顺序分发给不同 Agent,Worktrunk 的命令集很适合当底层调度原语。它的addexec都是无状态命令,你可以在任意一个自动化平台(比如 n8n 或者自己写的任务队列)里这样组合:

worktrunk add --name "$TASK_NAME" --desc "$TASK_DESC" --base main worktrunk exec "$TASK_NAME" -- "codex exec '$TASK_PROMPT'" worktrunk merge "$TASK_NAME" --base main --check-first --auto-clean

这个流程对应的就是一条完整的需求生命周期:创建任务、执行任务、验证并合并。你只需要在前面接一个任务拆解模型,后面接一个通知机器人,就成了一台非常简陋但能跑的"并行 AI 开发流水线"。我自己实测过,这种流水线处理"改 10 个不相关接口加日志"之类的机械任务,效率提升非常明显。

6.3 工具可以扩展的方向

Worktrunk 目前还很年轻,我后续计划加的功能包括:远程同步,把清单文件推送到远端仓库,让团队其他人也能看到任务状态;工作流插件,定义"每个任务必须跑linttest才能合并"这样的规则;Agent 报告自动沉淀,把每个任务对应的 Agent 输出保存成文档,方便回溯。

不过就算不加这些功能,光是"把 worktree 管理从 Git 底层命令变成任务级操作"这一点,就已经解决了并行 AI Agent 工作流中最让人头疼的目录混乱问题。工具不一定要大而全,把一个点的体验做透,价值就出来了。

最后分享一个我实际操作中的体会:并行 AI Agent 工作流能不能跑起来,工具只占一半,另一半是任务拆解的纪律性。文件改动的交集越小,Agent 之间的耦合越少,worktree 的优势就越明显。反过来,如果你拆出来的任务大量共享同一个文件,再好的隔离机制也只能做到"不互相踩脏工作区",合并阶段照样一地鸡毛。我的建议是先用 Worktrunk 跑一个改动范围完全隔离的实验任务,比如"给模块 A 加接口日志"和"给模块 B 修一个空指针",跑通一次之后,再慢慢增加任务之间的重叠度。等你能顺畅处理有公共文件交集的并行任务时,这套工作流才算真正上手了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询