十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Worktrunk:为并行AI Agent管理Git Worktree的CLI

Worktrunk:为并行AI Agent管理Git Worktree的CLI 最近这段时间我几乎每天都在跟并行 AI Agent 打交道。一边是 Codex CLI 在某个终端里吭哧吭哧写新功能一边是 Claude CLI 在同一个仓库里改另一个需求偶尔还有第三个 Agent 在处理紧急 bug。在没有 Worktrunk 之前这个场景对我来说就是灾难片现场git status 乱七八糟分支切来切去代码改到一半被另一个 Agent 的缓存搞懵最离谱的是有一次两个 Agent 同时动了同一个模块最后合并时冲突多到怀疑人生。后面我花了不少力气折腾 Git Worktree发现它天然就是为并行任务准备的但原生命令太底层管多了以后依然容易乱。于是就有了 Worktrunk 这个面向并行 AI Agent 工作流的 Git Worktree 管理 CLI。它是一个把任务和工作区绑定在一起的命令行工具帮你创建、切换、暂停和清理多个隔离的 Git 工作区同时为每个 Agent 分配独立的分支和目录避免互相踩脚。这篇文章我会把为什么要这样设计、具体怎么实操、以及我在真实使用中踩过的坑都讲清楚适合正在用 AI Agent 做开发、或者打算让多个 Agent 同时开工的朋友参考。1. 为什么我会写一个 Git Worktree 管理 CLI1.1 多个 AI Agent 同时改代码的崩溃现场先还原一下没做隔离时我遇到的真实状态。假设我现在在main分支上开着 Codex CLI 让它实现登录超时提示同时在另一个终端打开 Claude CLI 让它完善支付回调。两个 Agent 默认都读当前工作目录的代码于是它们面对的是同一个index.ts、同一份package.json。表面上看是并行实际是串行抢一把锁。Codex 刚把自己的改动写进文件Claude 那边可能已经缓存了旧版本内容再过几分钟就会拿旧内容覆盖新内容或者两个 Agent 都执行了npm install把node_modules里的依赖换成了各自需要的版本运行时的行为完全不可控。最要命的是你根本没法让它们同时工作只能等一个改完、提交、再让另一个上所谓的多 Agent 并行只是一个错觉。这个问题的根源不是 Agent 不够聪明而是它们共享了一份工作目录。要解决有两种常规路一种是把仓库完整 clone 多份给每个 Agent 一份独立副本缺点是硬盘占用翻倍、多个副本之间同步成本和出错的概率都很高另一种是不断git stashgit checkout切换分支但这种操作频繁做会丢上下文而且切换本身很伤 Agent 的思路连续性。两条路我试下来都不舒服。1.2 Git Worktree 正好补上这一刀Git Worktree 是 Git 从 2.5 开始提供的功能它允许同一个仓库同时存在多个工作目录每个工作目录可以检出不同的分支或提交。注意它跟 clone 的本质区别多个 worktree 共享同一个.git对象库不重复保存历史记录但工作区文件完全独立互不干扰。我打个比方一个普通 Git 仓库像一间只有一个工位的办公室你在这个工位上切来切去Worktree 相当于给每个任务单独开一间会议室会议室里各放一套图纸但所有会议室共用同一个档案室。档案室就是.git/objects图纸就是工作区文件。这样两个 Agent 各开一间会议室改得再凶也不影响对方。不过 Git 原生 worktree 命令用起来比较痛苦。你要手动git worktree add /path/to/dir -b feature/xxx main然后还得记清楚哪个目录对应哪个分支哪些任务在进行、哪些已经结束、哪些目录可以删除。任务一多目录一乱你根本不知道/Users/me/dev/repo-feature-payment到底是给哪个 Agent 用的、对应的是哪个任务、能不能安全删掉。对我来说缺的不是 worktree 这个机制而是围绕它的工作流管理。1.3 Worktrunk 的定位为 Agent 任务建一个车间Worktrunk 要做的事情就是把创建 worktree 目录这个底层操作抽象成创建一个任务工作区这个上层语义。你告诉它我想让 Codex Agent 去做修登录 bug 这个任务它会自动在约定的目录下创建 worktree、按规则命名分支、记录任务元信息后续你随时可以查看任务状态、暂停任务、唤醒任务、清理已完成任务的工作区。它不是重新实现一套 Git也不是 GUI 工具就是一个聚焦的 CLI主要干四件事初始化仓库的并行工作区目录结构、创建和管理任务工作区、展示当前并行任务的全貌、在任务结束后安全清理资源。对于正在尝试让多个 AI Agent 协作写代码的开发者它能把管理成本从每次手动敲一串 git worktree 命令降到一个单词任务名我觉得这个价值非常直接。2. Worktrunk 的核心设计把命令变成任务2.1 任务即工作区核心概念与命令模型Worktrunk 的中心概念是task。一个 task 代表一个独立开发任务它绑定了分支名、工作区路径、任务状态、所属 Agent 类型、基础分支、创建时间和备注。跟裸用git worktree的最大区别在于Worktrunk 在 Git 对象之外维护了一份任务清单让整个工作区是可浏览、可查询、可恢复的。命令模型我设计得很贴近实际工作流。比如# 初始化当前仓库 worktrunk init # 新建一个任务工作区基于 main 分支 worktrunk task new fix-login-timeout --base main --agent codex # 查看所有任务 worktrunk task list # 暂停任务保留现场 worktrunk task park fix-login-timeout # 恢复暂停的任务 worktrunk task resume fix-login-timeout # 标记任务完成并删除工作区 worktrunk task done fix-login-timeout # 清理所有已结束且无未提交改动的残留目录 worktrunk prune你会发现这些动词不是 Git 的习惯而是 Agent 工作流的动作创建任务、暂停、恢复、结束。Git Worktree 没有暂停和恢复的概念但人在管理并行任务时有Agent 在长时间跑一个功能时也有这就是 Worktrunk 存在的理由。2.2 元数据与状态管理任务表长什么样任务元数据存放在仓库根目录下的.worktrunk/目录里和.git/平级不会污染 Git 历史。每次执行worktrunk命令时工具会读取这个目录里的tasks.json文件再和真实的 Git worktree 状态做一次比对所以即使你手动用原生命令删了某个 worktreeworktrunk task list也能发现状态不一致并提示你处理。任务状态我划分得很简单只有四个状态含义可执行操作active任务正在进行工作区已就绪park/donepaused任务已暂停工作区可能不存在或未被检出resume/donedone任务已完成等待清理pruneorphan元数据存在但 worktree 已丢失reset/pruneorphan状态一开始没有后来是踩了不少坑才加的。比如有些同事不习惯用 Worktrunk会手动git worktree remove导致元数据里还有记录但真实目录没了。没有这个状态的话后续命令很容易报错。2.3 为什么做成 CLI而不是 IDE 插件或 GUI 工具市面上并不缺 Git GUI 工具但 Worktrunk 我坚定地做成 CLI。原因有两条。第一AI Agent 生态目前几乎全部长在命令行上。你写一个 VS Code 插件Agent 在无头环境或 CI 里跑的时候根本没法用你写一个 TUI 界面Agent 调用起来也很别扭。CLI 天然适合被脚本、Agent、CI 系统调用命令输入输出都容易解析。第二CLI 工具最容易保持轻量。Worktrunk 本质上是一组包装良好的 git 命令和文件状态机做成 CLI 可以避免图形界面带来的依赖和体积膨胀。它甚至可以设计成纯 shell 脚本但为了跨平台和可测试性我还是用 Go 写成了单一二进制文件没有运行时依赖拷到服务器上就能跑。对服务器上也能跑这是多 Agent 并行流水线很重要的一点。3. 从零开始五分钟搭一套并行 Agent 工作流3.1 安装与初始化一个二进制搞定Worktrunk 的安装方式取决于发行渠道。如果你用的是 macOS 且装了 Homebrewbrew install worktrunk就能搞定Linux 和 Windows 用户可以去 release 页面下载对应平台的二进制或者在有 Go 环境的机器上直接go install github.com/worktrunk/worktrunklatest。我推荐下载预编译二进制因为一个文件就能跑不污染环境。装好之后先验证版本$ worktrunk --version worktrunk version 0.4.2然后进入你的项目仓库执行初始化$ cd ~/projects/order-service $ worktrunk init ✅ Repository initialized: ~/projects/order-service Workspace root: ~/projects/order-service/.worktree初始化过程会做三件事检查当前 Git 版本是否支持 worktree低于 2.5 会直接报错、创建.worktree/目录作为所有并行任务工作区的统一根目录、生成.worktrunk/tasks.json空任务清单。这个.worktree/目录我建议写进.gitignore因为它只是本地工作目录不应该被提交。3.2 创建第一个 Agent 任务工作区假设我现在要让 Codex CLI 实现一个登录超时自动跳转的功能基础分支是main我执行$ worktrunk task new feat-login-timeout --base main --agent codex Creating worktree for task feat-login-timeout... Branch: feat-login-timeout Path: ~/projects/order-service/.worktree/feat-login-timeout ✅ Task feat-login-timeout is active.这个命令背后的逻辑值得展开说一下。Worktrunk 不会把工作目录直接放在仓库根目录下而是统一放在.worktree/task-name/里。这样有几个好处主工作区保持干净不会被并行任务的文件干扰所有任务工作区集中在一个目录结构一眼就能看清楚删除某个任务时只需要删除对应子目录风险可控。分支名默认和任务名一致如果任务名里有不合法的分支字符Worktrunk 会自动做转换比如feat login timeout会变成feat-login-timeout。创建完成后直接进入这个目录就能启动 Agent$ cd ~/projects/order-service/.worktree/feat-login-timeout $ codex这时候 Agent 看到的是一个干净的、基于main分支的独立工作区它在里面改任何文件、装任何依赖都不会影响主工作区里可能正在进行的其他操作。3.3 并行起飞同时管理多个 Agent 任务第一个任务跑起来之后我可以在另一个终端创建第二个任务交给 Claude CLI 去做支付回调的异常处理$ worktrunk task new fix-payment-callback --base main --agent claude Creating worktree for task fix-payment-callback... Branch: fix-payment-callback Path: ~/projects/order-service/.worktree/fix-payment-callback ✅ Task fix-payment-callback is active. $ cd ~/projects/order-service/.worktree/fix-payment-callback $ claude现在两个 Agent 分别在两个独立分支、两个独立目录里干活。Codex 在feat-login-timeout分支上改登录相关代码Claude 在fix-payment-callback分支上改支付相关代码两者共享同一个.git/objects但工作区文件互不可见不会出现一个改了另一个的文件这种问题。这时候worktrunk task list就能派上大用场$ worktrunk task list ID STATUS BRANCH PATH AGENT feat-login-timeout active feat-login-timeout .worktree/feat-login-timeout codex fix-payment-callback active fix-payment-callback .worktree/fix-payment-callback claude一眼就能看出当前有多少 Agent 在跑、各自在哪个分支、对应哪个目录。如果同时有七八个任务这个列表比你自己去翻git worktree list清晰得多因为任务名就是可读的而不是一串分支 hash 或者路径。3.4 收尾合并、暂停与清理Agent 完成任务后通常会在自己的 worktree 里提交代码并推送分支。这时候我去任务目录里检查 diff、跑测试确认没问题后合并到主分支$ cd ~/projects/order-service/.worktree/feat-login-timeout $ git checkout main $ git pull $ git merge feat-login-timeout --no-ff $ git push合并干净后用 Worktrunk 标记任务完成并清理$ worktrunk task done feat-login-timeout ✅ Task feat-login-timeout marked as done. Worktree removed: ~/projects/order-service/.worktree/feat-login-timeout如果某一天 Agent 任务做到一半你晚上要回家、或者想让它先暂停让出资源可以用park$ worktrunk task park fix-payment-callback Task fix-payment-callback paused. Worktree preserved. Run worktrunk task resume fix-payment-callback to continue.park做的事其实只是把状态改成 paused并不会真的删除 worktree但后续当你需要清理资源时prune会优先处理所有 paused/done 的目录。我个人习惯是晚上下班前把所有暂停任务都清理掉第二天早上靠git push的分支重新拉回现场避免一堆工作区在那占着硬盘和终端。4. 并行任务里的资源隔离与冲突控制4.1 Git 层面天然隔离是第一道防线Worktrunk 依赖 Git Worktree 天然提供的隔离能力这是整个并行工作流的第一道防线。两个 worktree 尽管共享对象库但工作区目录各自独立对同一个文件的修改不会直接覆盖对方各自的git status、暂存区、HEAD 都是独立的。这意味着两个 Agent 哪怕同时改同一个文件也只会各自在自己的 worktree 里留下修改最后在合并时才统一处理冲突。这点非常关键因为 AI Agent 在写代码时是盲改的它没有全局感知其他 Agent 改了什么。如果让它们直接操作同一个工作目录根本防不住互相覆盖但有了 worktree 这层隔离每个 Agent 的每一步操作都被封印在自己的区域里冲突被延迟到合并阶段。合并阶段的冲突是 Git 的强项有清晰的依赖图和三方对比比乱糟糟的覆盖好处理十倍。当然隔离不等于不会冲突。如果两个 Agent 都对同一个公共函数做了重构合并时依然要解决冲突。所以我在 Worktrunk 的任务模型里加了base概念所有短小任务都以同一个主干分支为基线尽量把涉及范围不同的任务并行公共模块的改动尽量拆成独立任务不要同时让两个 Agent 去大规模重构同一块代码。4.2 依赖与构建产物第二个坎Git 层面隔离之后下一个问题是依赖目录和构建产物。node_modules这种目录通常不会提交到 Git所以每个 worktree 都是空的需要各自安装依赖。如果每个 Agent 都跑一遍npm install不仅慢而且同一个依赖可能被安装两遍浪费磁盘空间。最难受的场景是Codex 安装依赖时把package-lock.json的版本升了而 Claude 在另一个 worktree 里用的是旧 lock两边的行为不一致。Worktrunk 提供了一个--shared-deps选项允许任务工作区通过符号链接共享主工作区的依赖目录。比如 Node 项目会尝试创建node_modules - ../../node_modules的符号链接Python 项目也可以把.venv指到主工作区的虚拟环境。共享依赖的好处是省空间、安装快坏处是依赖版本变化会影响所有任务而且有些构建工具不支持符号链接。我的建议是如果你的项目依赖比较稳定推荐用--shared-deps如果 Agent 经常需要新增依赖、更新依赖版本建议每个任务各自独立安装宁可多花一点磁盘空间也不要换来换去导致不可复现。实际操作中我一般默认不共享只有在启动很多同类 Agent 任务时才手动开共享。4.3 Agent 上下文与缓存隔离容易被忽略的细节Agent 工具本身也会在目录里缓存一些东西。比如 Codex CLI 会在项目目录里生成.codex/配置和会话历史Claude CLI 也可能保存 session 文件。如果两个 Agent 放在同一个项目目录下操作这些缓存会互相干扰Agent 甚至会把另一个 Agent 的历史对话当成自己的上下文。Worktrunk 做到任务目录隔离后这个问题基本没了因为每个 Agent 的缓存都被隔离在各自的 worktree 里。还有个细节是配置文件。很多 Agent 允许通过项目级配置文件覆写全局配置比如.codex/config.toml、CLAUDE.md。我们在 Worktrunk 初始化任务工作区时可以约定把这些规则文件统一复制到每个新任务目录里确保每个 Agent 开局都有一致的技能约束和权限边界。比如CLAUDE.md里写清楚不要修改公共类型定义、改动前必须跑测试、提交信息按约定格式Agent 在独立目录里也能遵守因为规则文件就在它眼前。5. 常见问题排查与避坑实录5.1 常见问题速查表用 Worktrunk 过程中遇到的问题大部分根子都在 Git Worktree 本身。下面是几个高频问题的速查表都是我真实踩过的。报错/现象直接原因解决方案fatal: path is already used by a worktree目标目录已被其他 worktree 占用换任务名或先git worktree remove pathfatal: a branch named xxx already exists分支名冲突同名分支存在换分支名或者用--force显式指定不同分支删除任务时提示工作区有未提交改动worktree 里存在 dirty 状态先进入目录确认改动确实不要了再prune --forcegit checkout main失败当前分支有未提交改动先在分支内 commit 或 stash任务状态显示orphan外部手动删除了 worktreeworktrunk task reset id修正状态主工作区git status显示一堆奇怪文件误把.worktree/目录提交进了 git把.worktree/加进.gitignore并git rm -r --cached .worktree5.2 三个最容易踩的坑第一个坑是让两个 Agent 同时修改同一个远端功能分支。我有一次创建了两个任务但 base 都指定成了同一个feature/api-refactor分支两个 Agent 各自在分支上提交推送后远端的分支线性历史直接被弄乱了其中一个 Agent 的推送被迫强推还差点覆盖另一个的工作。后来我在 Worktrunk 里严格约定每个任务必须创建自己的专属分支base 只允许选主干分支不允许任务之间共享同一功能分支。这样才能保证 push 安全。第二个坑是不看 worktree 隔离边界Agent 在任务目录里改了构建缓存导致主工作区编译异常。原本我想着共享node_modules省事结果 Codex Agent 在一个独立 worktree 里升级了依赖并重新生成 lock 文件影响的是符号链接指向的那一份真实依赖主工作区下次运行就报版本不一致的错。从那以后涉及依赖变更的任务我都关掉--shared-deps让它独立安装宁可慢一点也不要神不知鬼不觉地污染公共环境。第三个坑是 Windows 下的路径长度。Git Worktree 要在仓库根目录之外创建目录Windows 上如果项目路径本身就深再加上.worktree/task-name-xxx很容易超过系统默认的路径长度上限导致 checkout 时报错。这个问题我是在帮一个 Windows 用户排查时发现的。解决办法是把整个项目放在靠近盘符根目录的位置同时开启 Windows 的长路径支持或者干脆减少任务名的长度不要搞出一长串的描述性任务名。5.3 把 Worktrunk 融入日常的进阶玩法工具好用是一回事融入日常是另一回事。我这边有几个自己一直在用的小技巧。第一个是给 Worktrunk 设置 shell alias。我习惯把高频命令缩短成几个字母alias wtsworktrunk task list alias wtnworktrunk task new alias wtpworktrunk task park alias wtrworktrunk task resume alias wtdworktrunk task done这样在终端里打字几乎不费脑。更重要的是我写了一个简单的 shell 函数用wt task-name可以直接进入对应任务目录wt() { cd $(worktrunk task path $1) }第二个技巧是把 Worktrunk 和 tmux 结合起来。我会给每个 Agent 开一个独立的 tmux sessionsession 名就是任务名然后在 session 里启动对应的 Agent CLI。这样多个 Agent 并行跑的时候每个任务都有独立的终端环境我随时可以用tmux attach -t feat-login-timeout去观察某个 Agent 的输出而不会跟其他任务混淆。第三个技巧是配合 CI 和 Git Hook。我写了一个 post-merge hook在主分支合并完任务后自动执行worktrunk prune --done把已经合并到主分支的任务工作区清掉避免一堆结束任务目录堆积。CI 流水线里也可以加一步worktrunk task list --format json把当前正在进行的任务展示在构建日志里这样团队其他人一眼就能看到当前并行进行中的 Agent 任务有哪些。6. 写在最后的一些体会整个 Worktrunk 做下来我自己最大的体会是并行 AI Agent 编程真正难的不是让 Agent 更聪明而是让多个 Agent 在同一个工程里互不干扰地工作。Git Worktree 提供的是技术底子Worktrunk 把底子包装成了符合直觉的任务管理模型。现在我开新项目的第一件事就是worktrunk init然后开始批量创建任务工作区给不同 Agent 安排各自的分工。每个任务有自己的目录、自己的分支、自己的状态我再也不用担心它们在同一个工作区里互相折磨了。最后再分享一个小技巧如果你刚开始接触并行 Agent 开发不要一上来就开五六个 Agent 同时干活。先从一个任务起步跑通new → active → done的完整流程再尝试两个 Agent 同时跑不同模块等你对隔离边界、合并时机、资源占用都有感觉了再逐步加量。工具只能帮你不乱但哪些任务适合并行、哪些适合串行这个判断还是得靠自己。这一套流程我跑了大半年目前最顺手的组合是三个 Agent 一个主人主人负责 review 和合并Agent 负责在各自 worktree 里闷头写效率确实比单人单 Agent 高出一大截。
返回列表