2026/9/21 0:11:38

Worktrunk:用Git Worktree管理并行AI Agent工作区的实战复盘

Worktrunk:用Git Worktree管理并行AI Agent工作区的实战复盘 过去大半年我一直在折腾一件事同时让三四个 AI 编程 Agent 在同一个项目上并行干活。Codex CLI、Claude Code 这类工具确实能大幅提速但真正卡住我的不是模型能力而是 Git 仓库怎么扛住多路并发的写入。分支不够用、工作区互相污染、提交历史乱成一锅粥……这些问题反复出现之后我写了 Worktrunk 这个 CLI 工具专门用 Git Worktree 机制来管理并行 AI Agent 的工作区。这篇文章就是 Worktrunk 从设计到落地的完整复盘包括为什么需要它、核心功能怎么实现的、真实跑并行 Agent 工作流时怎么用以及我踩过的那些坑。1. 并行 AI Agent 工作流痛点到底在哪1.1 多 Agent 同时改代码仓库先“崩”了先说清楚我遇到的场景。一个中型项目功能拆成几个独立模块我用 Codex CLI 改后端接口用 Claude Code 刷前端页面再用另一个 Agent 处理数据库迁移。听起来很合理对吧但问题是它们默认都工作在同一个目录、同一条分支上。第一个撞上的问题是工作区互相覆盖。Agent A 改了文件 AAgent B 在跑测试的时候读到了已经被 A 改坏的中间状态直接报错。第二个问题是分支冲突。每个 Agent 我都给它分了独立分支但同一时刻它们都在跑git checkout切换分支Git 索引和工作区互相打架轻则报 Unable to update files 之类错误重则直接导致未提交的改动丢失。第三个问题是提交历史混乱。多路改动混在一条 develop 分支上review 的时候根本分不清哪段代码是谁改的、是给哪个需求写的。这不是 Git 本身的问题而是“多写者并发写同一工作区”这个模型本身就不对。你需要的是一个让每个 Agent 拥有完全独立工作区的机制而 Git 官方早就提供了这样的机制git worktree。1.2 Git Worktree并行开发的天然底座git worktree允许你在同一个仓库下维护多个工作目录每个目录可以独立检出不同分支互不干扰。它不像 clone 那样复制整个.git目录而是通过一个共享的 Git 元数据仓库来管理多份工作区既有隔离性又省磁盘空间。打个比方把仓库想象成一套房子的地基和骨架主工作区是客厅你用git worktree搭出来的每一个附加工作区就像是额外隔出来的房间。每个房间都有自己的门工作目录、自己的装修方案分支状态但水电管道Git 对象数据库是共用的。这个机制天然适配 AI Agent 的并行场景每个 Agent 分配一个独立 worktree各占一条分支互不干扰。但问题也随之而来——原生git worktree命令用起来非常繁琐。你需要在几个仓库之间来回切要记每个 worktree 对应哪个分支、哪个 Agent、任务进行到哪一步一多就乱。我自己最多同时开了 6 个 worktree光靠脑子记已经彻底失控。2. 手工管理 Worktree 的困境与 Worktrunk 的诞生2.1 三条手工命令三个现实痛点原生 Git 提供的基础命令其实就三条git worktree add创建、git worktree list查看、git worktree remove删除。听起来简单真正用起来全是坑。第一个痛点是状态不可见。git worktree list只能告诉你路径和分支但你不知道哪个 worktree 对应哪一个正在跑的 Agent也不知道它的任务进度、代码质量检查状态、哪些文件被改动过。一旦 Agent 数量超过三个这个问题就会让你疯掉。第二个痛点是创建流程繁琐。每个新任务你都得手动想一个分支名、想一个目录名然后执行git worktree add ../project-feature-xxx -b feature/xxx。如果忘了指定-bGit 会把同一个分支检到多个 worktree 里接下来就是一堆晦涩难懂的锁冲突报错。第三个痛点是清理极容易出错。任务完了Agent 跑完代码后可能还有未提交的改动、未合并的分支直接git worktree remove会报is dirty错误。你得先去 worktree 里手动处理或者用--force强删。强删一时爽代码火葬场我至少两次因为强删把还没 merge 的工作弄丢了。2.2 Worktrunk 的核心设计思路我基于这些真实痛点来设计 Worktrunk。它不是一个简单封装git worktree的脚本壳子而是一个真正面向 AI Agent 工作流的操作界面。核心设计原则有三条第一一切以任务为中心。用户眼中不应该是一堆路径和分支名而是“这个 worktree 是给哪个 Agent 用的、在跑哪个任务、状态如何”。Worktrunk 在创建 worktree 时自动生成任务元数据并持久化到仓库根目录下的.worktrunk/目录里。第二创建一条命令清理一条命令查询一条命令。把高频操作压缩到最少不需要用户记住十来个子命令。我见过太多工具为了显得强大把命令行搞得很复杂最后用户根本不想用。Worktrunk 的哲学是你要并行跑 Agent只记住worktrunk spawn就够了。第三状态透明。任何时候你输入worktrunk ps都能看到所有 Agent 工作区的实时状态——分支、最后活跃时间、改动文件数、dirty 状态。这有点像任务管理器的概念不过管理的对象是 Git worktree 而非进程。3. Worktrunk 的核心功能实现拆解3.1 命令体系spawn / ps / harvest / reapWorktrunk 的命令设计刻意与 AI Agent 的生命周期同步一共四个核心命令。worktrunk spawn负责创建新的 Agent 工作区。它接受两个参数任务名task name和 Agent 名称。执行后做的事情包括基于当前主分支切出新分支、创建独立 worktree 目录、生成元数据文件、把结果在终端里打印出来。在终端里你会看到类似这样的输出$ worktrunk spawn backend-refactor --agent codex ✔ 创建 worktree: backend-refactor 路径: worktrees/backend-refactor 分支: agents/backend-refactor 基于: main (commit 3f2ab81)worktrunk ps显示所有 Agent 工作区的状态表。它会逐个 worktree 检查 Git 状态统计改动文件数量、当前分支、最近 commit 时间、是否处于冲突状态等。输出是一张对齐的表格。命令的名字刻意模仿进程管理工具因为熟悉终端的人一眼就懂。worktrunk harvest是收尾操作它做的事比删除多一步先检查目标 worktree 是否有未提交改动有的话自动帮你生成一个 WIP commit 保存现场然后再清理 worktree 目录。这样即使代码还没达到合并标准也绝不会丢。如果改动已经都提交且分支已合并它会直接干净地移除相当于一句话完成“保障 清理”两件事。worktrunk reap是强制清理命令类似rm -rfgit worktree remove --force的组合但它会先打印待删除内容的完整清单并要求输入二次确认避免手滑。这三个命令加起来覆盖了一个 Agent 任务从开始到结束的完整闭环。3.2 状态持久化元数据不只是死数据Worktrunk 在.worktrunk/目录里为每个 worktree 维护一份 JSON 元数据文件记录的内容包括任务名、分配到的 Agent、创建时间、最后操作时间、当前分支、备注、以及一个可选的父任务 ID方便任务级别嵌套做依赖关系。{ taskName: backend-refactor, agent: codex, branch: agents/backend-refactor, worktreePath: worktrees/backend-refactor, createdAt: 2025-01-18T10:23:0008:00, lastActiveAt: 2025-01-18T10:45:0008:00, status: active, note: 重构用户模块的 service 层 }这份元数据不只是一个“标签”它是 Worktrunk 后续功能的地基。比如worktrunk ps可以按 Agent 过滤worktrunk harvest可以按创建时间批量清理旧任务未来还能做 Agent 维度的产出统计。在实际使用中我还发现它有一个额外好处当你同时跑多个 Agent 且时间跨了好几天时这份 JSON 就是你的项目开发日志一眼就能看出每个任务从哪来、干到哪、谁负责。3.3 面向 Agent 沙盒的隔离设计这一块是我认为最关键的工程决策。不同 AI Agent 的能力边界和工具栈完全不同Codex CLI 偏重全栈补全Claude Code 在涉及多文件重构时表现更稳定基于 MCP 生态的工具型 Agent 则适合处理脚本自动化。如果它们共享同一个工作区彼此的构建产物、依赖安装、环境变量会相互污染。Worktrunk 在 spawn 时做了三件隔离的事情第一默认在项目根目录下创建名为worktrees/task-name的目录结构让所有 Agent 工作区物理隔离、路径规则统一。第二每个 worktree 的.env文件由 spawn 命令生成里面注入WORKTRUNK_TASK和WORKTRUNK_AGENT两个环境变量。Agent 在代码里如果想知道自己身处哪个工作区直接读这两个变量即可不需要硬编码路径。第三worktree 默认不继承主工作区的未跟踪文件比如缓存的构建产物这样可以确保 Agent 从干净的基线开始工作避免把上一轮的临时文件当成项目内容来处理。4. 实操用 Worktrunk 跑通并行 Agent 工作流4.1 安装与环境准备Worktrunk 是一个单二进制 CLI安装非常轻量。它依赖本机的git2.30 以上版本即可因为要用到git worktree list --porcelain的稳定输出格式不需要额外装 Python 或 Node 运行时。我选择编译成静态二进制分发好处是用户拿到就能跑没有版本地狱。# 以 macOS 为例Linux 直接下载对应架构的二进制放在 PATH 里即可 curl -L https://github.com/yourname/worktrunk/releases/latest/download/worktrunk-darwin-arm64 -o /usr/local/bin/worktrunk chmod x /usr/local/bin/worktrunk worktrunk --version如果你用的是真实项目我的建议是在项目根目录先跑一次git worktree list看看目前有没有已存在的 worktree接着worktrunk init会生成.worktrunk/config.toml里面可以配置默认的 Agent 列表和工作区目录前缀。配置好后你的并行开发环境就绪了。4.2 一次完整的并行任务实操假设我现在要同时做三个任务后端接口重构、前端页面调整、数据库脚本编写。我打开终端连续执行三次 spawnworktrunk spawn backend-refactor --agent codex worktrunk spawn frontend-polish --agent claude worktrunk spawn db-migration --agent zcodeWorktrunk 会给每个任务创建独立工作区和分支。接下来我分别进入对应目录启动各自的 Agent CLIcd worktrees/backend-refactor codex cd worktrees/frontend-polish claude cd worktrees/db-migration zcode这里有一个我自己摸索出来的经验不要让 Agent CLI 在后台长期驻留而是让它们在前台工作、输出到各自的日志文件。比如用codex /tmp/agent-backend.log 21 重定向到文件。这样一旦发现问题直接翻对应任务的日志不会三条 Agent 的输出混在一起。你的主终端只保留一个窗口不停地跑worktrunk ps看全局状态。4.3 最关键的一步让 Agent 写完代码后自动保存现场并行 Agent 最危险的时刻是它认为自己“做完了”而实际代码还没合并的时候。Agent 工作区的分支躺在那里改动散落在未提交的文件里状态不明确。Worktrunk 对这个场景提供了一套收敛流程# 1. 查看全局状态 worktrunk ps # 2. 对某个任务做快速复核切到它的工作区看改动 cd worktrees/backend-refactor git diff --stat git log --oneline -5 # 3. 改动符合预期提交代码这里可以让 Agent 自己写 commit message cd ../.. # 4. 任务收尾harvest 会自动保存未提交改动并清理工作区 worktrunk harvest backend-refactorharvest执行结束后worktrunk ps列表里不再出现这个任务但分支agents/backend-refactor还在远程。如果你想把它合回主分支在项目根目录跑一句普通的 merge 即可git checkout main git merge agents/backend-refactor worktrunk reap backend-refactor # 确认合并没问题后再彻底清理残留这套流程走顺之后我在一天内可以同时推进 5 个独立任务而不会互相干扰提交历史也干净清晰。每条分支对应一个可追溯的任务review 的时候能按分支逐个看。4.4 关于分支策略的建议用 Worktrunk 跑并行 Agent 时我建议分支命名规则固定为agents/task-name。这样做有两个好处一是过滤和清理时能一眼看出哪些分支不是主线开发分支二是配合 Git 的 branch 保护和 CI 触发策略很方便地让agents/*分支走独立的校验管道不污染主分支的 CI 结果。如果你在公司公共仓库上操作还要注意一件事Agent 生成的分支不要直接推送到共享远程仓库无人认领的位置最好在harvest之后由人来 review再推到远程。在只跑本地实验时可以不推远程全部在本地收尾这样远程仓库的历史完全不受影响。5. 常见问题与排查技巧实录5.1 典型问题速查表以下是我在这段时间里实际遇到的最常见问题以及对应的排查思路。情景现象原因处理方式worktree 无法创建报错already exists分支或目录名冲突用git branch -a查分支改任务名再执行 spawnagent 改完代码后 worktree 状态是 dirtyworktrunk ps显示未提交改动Agent 结束时未做 commit这是常态而非异常直接 harvest它会自动生成 WIP commit 暂存多个 agent 都从 main 分支拉新分支各自演进后 merge 冲突并行开发时间过长主分支变动太多定期让 Agent 从 main rebase冲突由 Agent 自行解决worktree 卡在 locked 状态git worktree remove提示 lockedAgent 异常退出导致锁未释放使用git worktree unlock path后重试harvest执行时报错找不到元数据旧 worktree 没有对应 JSON 文件该目录由手工 git worktree 创建用worktrunk import path --task name导入为受管工作区5.2 独家避坑技巧第一个技巧是不要让 Agent 在工作区里安装全局依赖。比如 Node 项目Agent 很容易跑一个npm install -g或者把node_modules装到上级目录。为避免这个我在 spawn 时生成的.env里固定了npm_config_prefix和PYTHONPATH这类环境变量让依赖都落在当前 worktree 内避免多个 worktree 共享一套依赖导致版本错乱。第二个技巧是给每个 worktree 配独立的 Git 用户邮箱。我见过 Agent 提交代码时把邮箱写错导致整个提交历史被污染所以 Worktrunk 在创建 worktree 时会自动设置局部的user.name和user.email比如codex-agentworktrunk.local这样 review 时一眼就能识别哪条提交是哪个 Agent 生成的。第三个技巧可能比前面两个更值钱并行 Agent 不等于并行任务无限制。我实测下来同一仓库最多同时跑 4 个 Agent 是比较舒服的。超过这个数不仅 Git 的锁竞争开始明显拖慢操作速度模型上下文切换的成本也会让每个 Agent 产出质量下降。与其开十个 Agent 各写一点不如四个 Agent 深挖各自模块最后统一做集成测试。6. 工具选型对比与适用场景思考有人可能会问为什么不用现成的 Monorepo 工具或者临时写个 shell 脚本就行我的回答是脚本能解决“创建”这一步但解决不了“管理”和“状态可视化”这两步。市面上确实有一些基于 Git Worktree 的第三方工具比如git worktree manager之类的我在早期也试用过。它们擅长管理静态开发环境但完全没有考虑 AI Agent 这个新物种的行为模式Agent 不会主动遵守你的清理流程不会在结束时提交代码时不时会把工作区玩坏。Worktrunk 的 harvest 机制和元数据设计本质上是为“不可靠的劳动者”兜底。适用场景我给你划个范围。如果团队或个人的开发模式是一个需求拆成多个模块、并行推进、期望每个模块的变更历史独立可靠那么 Worktrunk 值得一试。反过来如果你只是单人在单分支上线性开发Agent 只用来写写辅助脚本那这个工具给你带来的管理开销会大于收益原生git worktree add就够了。从技术实现角度补充一句Worktrunk 的命令执行速度本身很快因为大部分操作只是调用git worktree子命令加读写一个 JSON 文件。所有耗时操作都在git侧工具本身不会成为性能瓶颈。这也是我在设计时坚持的另一个原则能交给 Git 原生能力做的事绝不在工具层重复造轮子。7. 后续扩展方向与一点个人体会这个项目目前已经能稳定支撑我日常的并行 Agent 开发我计划给它加两个功能。一个是 worktree 级监控定时自动抓取每个工作区的代码变更摘要并汇总呈报相当于给并行 Agent 配一个“看板”。另一个是冲突预警在多个 worktree 同时改到同一批文件时主动提醒把集成阶段的问题提前暴露。最后说一点个人体会。搞 Worktrunk 这几个月我最大的收获不只是终端里多了一个好用的命令而是想明白了一件更底层的事AI Agent 的工程化落地真正的瓶颈往往不在模型能力而在开发者基础设施能不能跟上。Git 虽然是四十多年前的设计但它提供的“把状态隔离在独立工作区”这一思想反而在 AI 并行开发时代变得格外关键。工具只是把正确的工作流固化下来难的从来都是搞清楚正确的工作流是什么。希望这篇文章能帮你少踩几个我踩过的坑。