公司动态
用Git Worktree为AI Agent构建可靠的多仓库工作区
如果你以为“Agent 写代码”的瓶颈是模型不够聪明那大概率还没遇到真正的麻烦。真实项目里Agent 往往不是在一个干净的单仓库里工作而是要同时面对多个 Git 仓库、多个分支、多个任务甚至多个 Agent 并行改代码。这个场景下大多数工具的做法是先给代码库建立一套索引再把索引喂给模型。听起来很合理但实际用起来却有一个很尴尬的问题——索引里的代码永远是“过去时”。最近看到的一个新项目标题是Show HN: Orbit - One agent across many repos: real worktrees, no index虽然项目细节还不算多但这个标题本身非常值得拆解。它把 Agent 工具的两个关键设计选择摆在了台面上第一用真实的 Git worktree 来管理 Agent 的工作区第二不建索引不维护那套“二手”的代码上下文。这篇文章我想从工程角度讲清楚为什么这个设计思路值得关注以及你在自己的项目里怎么用 Git worktree 给 Agent 搭一个可落地、可验证、可回滚的工作区。1. 多仓库 Agent 的真实痛点代码上下文从哪来先还原一个常见的开发场景。假设你负责一个微服务项目服务 A 依赖团队内部的公共库 common-lib。某天产品要求改一个跨服务的接口协议你需要同时修改 service-a 和 common-lib改完一起联调。人肉开发时你会打开两个 IDE 窗口一边改公共库一边改调用方最后分别提交、发布。换成 Agent 来做这件事第一步就卡住了它怎么同时“看到”两个仓库的代码目前主流做法大致有三类让大模型直接读文件路径靠长上下文硬扛。简单但 token 消耗大而且仓库一大模型很快会“忘掉”前面读过的内容。给代码库建立索引包括向量索引、符号索引、调用关系图然后通过检索把相关代码片段塞给模型。这是当前很多 Agent 工具的实际做法。把每个仓库真实地 checkout 到一个工作目录让 Agent 在真实文件系统里读写文件再通过 git diff、git status 观察改动。Orbit 的标题指向的正是这条路线。第三种方案看起来最“笨”但它解决了一个索引方案很难彻底解决的问题上下文一致性。索引本质上是代码库的一份压缩快照。快照意味着它会过期。Agent 改完代码后索引可能还停留在旧状态Agent 检索时可能找到的是已经被自己改掉的旧函数更麻烦的是多仓库场景下每个仓库都有自己的索引索引之间还可能互相矛盾。最后 Agent 输出的代码看起来自信满满但你去 git diff 一看改的位置根本不对。所以在多仓库场景里“上下文管理”比“模型智商”更影响最终效果。这也就是为什么 “no index” 能成为一个卖点——因为它有意绕开了索引维护这个最大的不稳定因素。2. 索引方案的三个坑为什么“no index”可以成为卖点先说清楚索引不是贬义词。IDE 的符号跳转、代码搜索、静态分析工具都依赖索引。但在 AI Agent 这个场景下索引有几个绕不开的坑。2.1 索引更新天然滞后代码是高频变动的。开发模式是先写代码再运行再改。索引的建立却往往是异步的、批量的、按文件粒度扫描的。Agent 刚把某个文件改了索引还没来得及重新生成下一个任务检索到的还是旧内容。如果 Agent 基于旧内容继续改就会产生冲突。这还不是最可怕的。最可怕的是 Agent 不会像人一样察觉到“我拿到的信息可能过期了”。它会非常自信地用旧接口、旧函数签名生成新代码然后告诉你“已完成”。2.2 检索质量不稳定索引方案把“理解代码”变成了“检索代码”。Embedding 向量检索本身就有概率性它可能把语义相似但完全不相关的文件排在前面也可能漏掉真正关键的调用关系。人肉审查时一眼能看出的问题检索阶段就已经埋下了。很多做过 RAG 的开发者都有体会RAG 方案的最终效果往往取决于“检索到的内容对不对”而不是“生成模型强不强”。代码检索的难度比文档检索更高因为代码的结构化信息函数调用、类继承、变量作用域很难用纯向量的方式精确表达。2.3 多仓库索引管理复杂单仓库索引已经够麻烦了多仓库还要考虑每个仓库的索引范围怎么配置公共库的索引更新要不要触发依赖方 Agent 的重新检索按任务隔离索引还是按仓库全局共享一份索引索引存储在哪里会不会成为新的基础设施负担这些问题不是不能解决而是解决成本很高。一旦索引成为 Agent 工作流里的核心依赖你就多了一个需要监控、维护、排障的中间层。Orbit 的 “no index” 就是对这个趋势的逆反既然索引问题这么多那我不建索引了直接让 Agent 使用真实代码。一句话总结索引是“记忆的压缩”而压缩必然有损真实 worktree 是“直接看现场”虽然不够优雅但不会失真。3. Git Worktree 是什么为什么 Agent 应该使用真实 Worktree先补一个基础概念很多开发者对 git worktree 不太熟。Git worktree 是 Git 官方提供的一个功能让你在同一个仓库上同时拥有多个工作目录。每个工作目录可以 checkout 不同的分支共享同一个.git对象库但互不干扰。传统用法是你正在 main 分支写代码突然要修一个线上紧急 bug又不想把当前改到一半的文件 stash 掉于是用git worktree add在另一个目录里 checkout 一个 hotfix 分支改完再回来继续原来的工作。这个功能对 Agent 来说价值被放大了。先看基本命令# 在项目根目录执行查看当前状态 git status # 基于 main 分支创建一个新的 worktree并新建 agent-demo 分支 git worktree add ../service-a-agent-demo -b feat/agent-demo main # 查看当前仓库所有的 worktree git worktree list # 退出 worktree 目录后删除它 git worktree remove ../service-a-agent-demo执行完git worktree add后你会得到一个全新的目录../service-a-agent-demo里面是完整的仓库文件但 checkout 在新建的feat/agent-demo分支上。你在里面改代码不会影响到主工作目录。这对 Agent 的意义在于Agent 操作的是真实的文件系统和真实的 Git 状态而不是模型内存里的模拟状态或索引里的快照。具体来说worktree 方案带来四个直接好处隔离性。每个任务一个独立 worktreeAgent A 在 feature-a 分支上改Agent B 在 feature-b 分支上改互不污染。可验证性。Agent 改完代码git diff直接能看到改动git status能看到新增和删除的文件运行测试也变得自然因为它真的在一个完整的工作目录里。可回滚性。worktree 基于分支工作改坏了就git checkout丢弃或者直接删除 worktree 重建代价很低。零状态成本。没有索引、没有缓存、没有向量数据库代码就静静地躺在文件系统里Agent 需要什么就读什么。用一句话类比索引方案是给 Agent 看地图worktree 方案是带 Agent 去现场。地图是静态的现场才是真实的。这里还要澄清一个容易混淆的点Git 里的 index 和这里说的 index 不是一回事。Git 的 index 是指暂存区也就是你git add之后、git commit之前存放改动的地方Orbit 标题里的 no index指的是不维护一套额外的代码检索索引比如向量索引、符号索引。不要被术语搞混。4. Orbit 的设计思路拆解One Agent Across Many Repos从项目标题可以拆出三个关键词One agent、many repos、worktrees no index。4.1 One Agent Across Many Repos 到底解决什么“一个 Agent 横跨多个仓库”这句话的关键不是“一个”而是“横跨”。它意味着 Agent 不是单独处理某个仓库内的局部任务而是能理解仓库之间的依赖关系在一个任务里同时操作多个仓库的代码。典型的场景包括跨仓库 API 变更公共库改了接口所有调用方仓库同步修改。批量依赖升级多个仓库同时升级某个底层库解决兼容问题。配置统一调整多个服务仓库同时改统一配置、环境变量、CI 流程。跨服务 bug 修复问题涉及服务 A 的调用逻辑和服务 B 的返回结构需要两边同时改。这些任务对 Agent 工具的要求不只是“能写代码”还包括“知道去哪里改代码”“知道改完后如何验证”“知道改动是否完整”。在多仓库环境下这些能力高度依赖工具对仓库状态的精确表达。4.2 Real Worktrees 是手段No Index 是态度“Real worktrees”说明这个项目在工程实现上选择了真实文件系统作为 Agent 的操作对象。这意味着Agent 可以直接用常规工具链grep、find、sed、编译器、测试框架处理代码。Agent 的每一步改动都在 Git 的掌控之下。人工审查时可以像审查同事代码一样直接看 diff 和 commit。“No index”说明这个项目拒绝维护一套额外的代码知识库。这个选择的潜台词是与其花精力让索引跟上代码变化不如让 Agent 按需读取真实代码用完即弃任务结束就关闭 worktree。从架构上讲这是一个更简单的设计。少一个组件就少一类故障。索引系统常见的问题——更新滞后、检索不准、存储膨胀、权限管理——在 no index 的设计下一并消失了。当然no index 也有代价。如果 Agent 需要频繁检索大规模代码库或者需要跨很多次对话积累对代码库的长期记忆那索引可能还是必要的。worktree 方案更适合“短期、聚焦、可交付”的任务而不适合需要长期记忆的复杂重构。4.3 这个设计思路偏好在哪如果只看表面很容易误以为“no index”就是反对 RAG、反对代码检索。其实更稳妥的判断是Orbit 在做一种任务类型的选择——它更关注“让 Agent 在多仓库场景下不出错地完成任务”而不是“让 Agent 更快地找到相关代码”。对开发者来说这两种价值取向完全不同。前者强调结果可靠后者强调运行效率。如果你正在用 Agent 做自动化任务可靠性通常比效率更重要。一个改了 30 个文件但其中 3 个改错的 Agent和一个改了 20 个文件但全部正确的 Agent你选哪个答案不言而喻。5. 动手实践用 Git Worktree 搭建 Agent 友好的多仓库工作区Orbit 的具体使用方式要以官方仓库和文档为准。但它的核心思路你可以用原生 Git 命令先跑通理解它的工作原理。下面演示一个模拟场景一个任务需要同时修改 service-a 和 common-lib 两个仓库我们为每个仓库创建一个独立 worktree让 Agent 在两个真实目录里工作。5.1 准备两个仓库# 模拟环境创建两个本地仓库 mkdir -p ~/code/orbit-demo cd ~/code/orbit-demo # 创建 common-lib 仓库 git init common-lib cd common-lib echo def helper(): helper.py echo return old helper.py git add . git commit -m init common-lib cd .. # 创建 service-a 仓库 git init service-a cd service-a echo from helper import helper main.py echo print(helper()) main.py git add . git commit -m init service-a cd ..这个场景里service-a 依赖 common-lib 的 helper 函数。我们要做的任务是把 common-lib 的返回值改成new并同步修改 service-a 的调用方式。5.2 为每个仓库创建 Agent 工作区cd ~/code/orbit-demo/common-lib git worktree add ../agent-common-lib -b feat/agent-update main cd ~/code/orbit-demo/service-a git worktree add ../agent-service-a -b feat/agent-update main # 查看所有 worktree git worktree list执行后你会看到四个目录common-lib主工作区agent-common-libAgent 工作区service-a主工作区agent-service-aAgent 工作区Agent 的操作全部限定在agent-common-lib和agent-service-a中不会干扰你的主工作区。5.3 在 Agent 工作区中修改代码这一步可以手动模拟 Agent 的操作也可以由 Agent 工具执行。# 修改 common-lib 的 helper.py cd ~/code/orbit-demo/agent-common-lib sed -i s/old/new/ helper.py git status --short git diff预期输出M helper.py diff --git a/helper.py b/helper.py index 5f8a9c2..d3e4f5a 100644 --- a/helper.py b/helper.py -1,2 1,2 def helper(): - return old return new再修改 service-a 的 main.pycd ~/code/orbit-demo/agent-service-a sed -i s/print(helper())/print(result, helper())/ main.py git status --short git diff预期输出M main.py diff --git a/main.py b/main.py index 7c8d9e0..1a2b3c4 100644 --- a/main.py b/main.py -1,2 1,2 from helper import helper -print(helper()) print(result, helper())5.4 验证改动在 agent-common-lib 中运行测试cd ~/code/orbit-demo/agent-common-lib python3 helper.py在 agent-service-a 中运行主程序注意你需要保证 agent-service-a 能访问 agent-common-lib 的模块实际工程中通过依赖安装解决cd ~/code/orbit-demo/agent-service-a python3 main.py如果输出中包含result new说明两个仓库的改动是配套的任务完成。5.5 完成与清理确认改动无误后可以提交并删除 worktree# 在 agent-common-lib 中提交 cd ~/code/orbit-demo/agent-common-lib git add . git commit -m feat: update helper return value # 在 agent-service-a 中提交 cd ~/code/orbit-demo/agent-service-a git add . git commit -m feat: update service-a call # 回到主工作区清理 worktree cd ~/code/orbit-demo/common-lib git worktree remove ../agent-common-lib cd ~/code/orbit-demo/service-a git worktree remove ../agent-service-a # 查看清理后的状态 git worktree list这个流程的核心是Agent 的所有改动都发生在独立分支和独立目录中人工可以随时介入、审查、回滚。整个过程没有创建任何索引没有配置任何向量数据库没有维护任何额外状态。6. 运行结果与效果验证对于 “Agent worktree” 这种模式验证是否成功不能只看“代码有没有生成”还要确认三件事。6.1 改动是否精确命中目标用 git diff 检查改动应该只包含任务相关的文件不应该出现无关文件被误改。git diff --stat如果输出里混入了大量与任务无关的文件说明 Agent 的工作目录配置有问题或者任务描述不够清晰。6.2 改动是否可追溯用 git log 查看提交历史。git log --oneline -5每个提交都应该对应一个明确的任务单元。如果 Agent 一次提交塞了几十个文件的改动后续 review 和回滚都会很痛苦。6.3 任务是否可以重复执行worktree 的优势在于任务结束后删除 worktree下次任务重新创建。这保证了每次任务的环境是干净、一致的。git worktree list如果列表中出现残留的 worktree说明上次任务没有正常清理。建议在 CI 或编排层增加清理机制。失败排查的第一步永远是让 Agent 先运行git status和git worktree list确认当前它到底在哪个目录、哪个分支、改了什么。很多问题不是模型能力不够而是 Agent 自己都搞不清状态。7. 多仓库 Agent 场景下的常见风险与排查Worktree 不是银弹实际使用中有很多细节容易踩坑。7.1 Worktree 无法删除问题现象可能原因排查方式解决方案git worktree remove失败工作目录有未提交改动git status查看状态先提交、stash 或丢弃改动删除后仍出现在git worktree list目录被手动删除元数据残留git worktree list --porcelain检查执行git worktree prune清理过期记录一个必须记住的限制同一个分支不能被两个 worktree 同时 checkout。如果 Agent 试图在第二个 worktree 里 checkout 一个已经被占用的分支Git 会直接报错。fatal: feature-branch is already checked out at ...这时要么让 Agent 换一个分支名要么先关掉占用该分支的 worktree。7.2 Agent 改错了仓库多仓库场景下Agent 很容易在切换目录后迷失方向。比如它以为自己在 service-a实际却在 common-lib 里改了代码。解决办法在给 Agent 的指令里明确要求它每次执行前先运行pwd和git status确认自己所在位置。也可以把 worktree 的目录名设计成任务相关的标识减少混淆。下表是更一般的排查参考问题现象可能原因排查方式解决方案Agent 基于旧代码生成修改索引方案中的索引未更新检查索引刷新策略worktree 方案下直接以git status/git diff为准改动无法通过编译公共库接口变更未同步查看两个仓库的 diff先改公共库并验证再改调用方多 Agent 并行任务互相干扰两个 Agent 操作同一个 worktreegit worktree list查看占用一个任务对应一个独立 worktreeWorktree 目录过大仓库体积大或包含大量生成文件du -sh查看目录大小使用.gitignore排除生成文件或使用稀疏检出Agent 出现幻觉声称“已完成”没有设置验证步骤检查 Agent 是否执行了测试命令在任务规范中强制要求运行测试并贴出结果7.3 不要把 worktree 当作生产环境Worktree 是开发环境不是生产环境。它适合做代码修改、测试验证、分支开发但不要在上面跑长时间运行的服务也不要当作发布环境。生产部署应该走正常的 CI/CD 流程基于完整的代码构建和发布。8. Agent 工具选型与工程实践建议看完上面的分析你可能会问那我到底该用索引方案还是 worktree 方案我的建议是不要二选一而是按任务类型来选择。8.1 什么样的情况适合 worktree 方案任务是短期的、聚焦的明确指向某个仓库或跨仓库的一组改动。你要的是“结果正确”而不是“过程最快”。团队有 Git 基础知识能理解 worktree 的分支隔离逻辑。你希望 Agent 的改动可以被人工 review 和回滚。你不希望引入额外的索引基础设施。典型场景批量升级依赖、跨仓库 API 变更、配置统一修改、自动修复 lint 问题、生成测试用例。8.2 什么样的情况适合索引方案任务需要长期理解整个代码库比如“给我解释一下这个项目的整体架构”。任务涉及跨大量文件的检索和探索Agent 需要快速定位“最相关的代码在哪里”。代码库非常大单次任务无法把所有代码都读进上下文。你不介意维护索引的额外成本并愿意接受索引更新滞后带来的风险。典型场景代码问答、技术债分析、架构梳理、大规模代码搜索。8.3 团队工程实践建议如果你决定在项目里尝试 “Agent worktree” 模式以下几条建议值得认真对待。第一规范任务命名。每个 Agent 任务创建一个独立分支和独立 worktree建议使用任务 ID 作为分支名例如feat/task-1234-update-helper。这样从分支名就能看出这个 worktree 是干什么的。第二强制验证步骤。给 Agent 的任务指令里必须包含运行测试、查看 diff、确认改动范围的步骤。不要把“检查”交给 Agent 自觉要用流程约束。第三设置权限边界。Agent 的工作区应该做最小权限控制。不要让 Agent 访问生产环境的密钥不要把生产数据库的连接串放在 Agent 能读到的配置文件里。安全边界和人工开发一样甚至要更严格。第四定期清理。在 CI 或定时任务里增加 worktree 清理逻辑避免残留 worktree 堆积。# 清理所有已经不存在的 worktree 元数据 git worktree prune # 查看当前所有 worktree 及其分支 git worktree list第五把 “No index” 理解为“无状态优先”。Agent 任务应该是可重复的、可从干净状态重新开始的。如果某个任务依赖上一次执行留下的状态那就是设计出了问题。8.4 关于多 Agent 协作如果你在编排多 Agent 协作worktree 的隔离性会非常有用。每个 Agent 拿到一个独立 worktree跑完任务后把分支推送到远端再由人工或 CI 统一合并。这样的模式天然避免了一个 Agent 的改动覆盖另一个 Agent 的改动。相比之下多个 Agent 共享同一个工作目录的方案几乎一定会出现冲突。除非用锁机制否则不建议让多个 Agent 同时操作同一份文件。9. 总结回到 Orbit 这个项目。“One agent across many repos: real worktrees, no index” 这个标题真正有价值的地方不是“它又造了一个 Agent 工具”而是它提醒我们Agent 工具的设计并不只有“给模型塞更多上下文”这一条路。Worktree 方案让 Agent 站在真实代码上工作而不是站在索引快照上工作。它放弃了检索效率换来了状态的真实性和可回滚性。在跨仓库修改、批量升级、接口变更这类高风险任务里这个交换是划算的。对于普通开发者你不需要等 Orbit 正式发布才能用上这个思路。直接用 Git 原生 worktree就能为 Agent 建立干净、隔离、可验证的工作区。先把这一步跑通再决定要不要引入更完整的工具。下一步可以做的事很清楚打开一个你手头真正需要跨仓库修改的项目用git worktree add建一个 Agent 工作区给 Agent 一个明确任务然后观察它是否能在正确的位置、正确的分支上做出正确的改动。这一套流程跑通之后你对 Agent 工具的选型会有一个完全不同的判断标准。