前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
返回 AI 情报前线
All News · 全部资讯9915
  • LocalRAG 开源本地文档问答完整链路
  • Copilot群聊支持在同一对话处理多个仓库
  • Agent 执行工具前需要哪些安全关卡
  • 让 Claude Code 参考后端而不误改代码
  • Opus 快速模式开放,提速成本需细算
  • 让编程 Agent 看懂仓库依赖关系
  • 分类与抽取任务可让模型直接选答案
  • 为付费 API Agent 强制设置支出上限
  • n8n 长任务先响应,避免超时重试
  • Meta 新开放权重模型支持苹果芯片本地运行
  • 英伟达推出百万上下文开放多模态 Agent 模型
  • 用Claude Code做手机声波联机游戏
  • Google OAuth 支持刷新令牌密钥绑定
  • 将低频流程移入 Claude Code 按需技能
  • Copilot 多模型编排需累计计算调用费用
  • Gemini CLI 消费者登录退役带来的迁移提醒
  • 编码智能体自动放行配置可能成为攻击入口
  • 用事件钩子识别编码智能体何时等待操作
  • 并行编程 Agent 背后的 Git 工作树机制
  • Copilot 部分模型将于11月16日退役
  • NoteBank 用片段回放补强长上下文记忆
  • Meta 推出8160亿参数开放权重多模态模型
  • 两台 M5 Ultra Mac 可运行 Muse 开放模型
  • SageMaker 支持部署 Muse Spark Open
  • 谷歌 ADK 配方库贯通 Agent 开发部署
  • 为多轮 Agent 建立持续评估流水线
  • ctxtrim 压缩日志,节省编程上下文
  • 技能触发不准,先改好 description
  • AI 生成页面上线前,补验 GA4 事件链路
  • 让客服机器人把处理结果反馈到检索排序
  • Muse Spark Open 发布,主打编程与 Agent
  • FLUX 3 Klein 开放权重,8GB 显存可运行
  • Gemini 4 Argon 整合机器人控制与仿真
  • 英伟达开放多模态模型,面向企业智能体
  • Vercel 扩展后端与 Agent 部署能力
  • 英伟达发布面向智能体的多模态开放模型
  • 英伟达扩充智能体模型,覆盖云端与本地
  • 日合并超三万次,Anthropic 重构版本控制
  • CLiF 将智能体运行记录转为训练评测资产
  • GitHub 代码扫描智能体修复正式可用
  • Webhook 驱动 Agent 的可靠性要点
  • 用 TypeScript 为 Agent 补齐应用连接器
  • 177 项科研技能补齐智能体领域知识
  • 发现 AI 擅自决策:简单审查胜过复杂流水线
  • WhatsApp 智能体上线后的工程难题
  • Netflix 为编程智能体接入 IDE 代码分析引擎
  • PentAGI 用多智能体执行渗透测试
  • MCP 排错日志里的凭据泄露隐患
  • Jev新版加入图像输入与26.2万上下文
  • 已加载 49 / 9915
8.0
热点
AI SCORE
编程提效2026-10-16 03:35

并行编程 Agent 背后的 Git 工作树机制

dev.to · AI#Git#Agent#并行开发
Editor brief · 编辑速览

文章解释多个 Git 工作树如何隔离任务目录与分支,同时共享对象库、分支引用和钩子。作者结合自身 IDE 的实践介绍并行 Agent 的底层机制,并提供可在临时仓库验证的思路。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

书籍:LLM Observability Pocket Guide

系列:Pocket Guides for Developers——8 本短书,涵盖 Agent、RAG、prompt、可观测性、事件、数据库和系统设计——完整系列

我的项目:Hermes IDE | GitHub——面向使用 Claude Code 等 AI 编程工具交付软件的开发者的 IDE

关于我:xgabriel.com | GitHub

启动五个编程 Agent,分别处理五项任务,你会得到五个文件夹、五个分支和五个终端。但你仍然只有一个仓库。这些 Agent 创建的每个 commit 都会进入同一个对象存储,它们创建的每个分支也都会出现在同一份引用列表里。hook 只需安装一次,五个 Agent 都会运行它。

这就是 git worktree 的设计,也是大多数并行 Agent 工作方式的底层基础。我开发的 Hermes IDE 也使用了它:每项任务都有自己的 hermes/<name> 分支,并在独立的 worktree 中运行(README)。阅读文中涉及 Hermes 的部分时,请把我与这个项目的关系考虑在内。至于 git 部分,讲的都是 git 本身的机制,你可以花几分钟,在一个实验仓库里逐一验证。

下文没有粘贴终端输出。我描述的每个结果,都来自文中引用的 git 文档、源码和发布说明。你可以运行这些命令,对照自己的实际结果。

在实验仓库里创建五个检出目录

创建一个临时仓库,提交一个空 commit,再添加五个关联 worktree,每个 worktree 对应一个分支:

mkdir -p ~/code/wt-lab && cd ~/code/wt-lab
git init -q -b main acme && cd acme
git commit -q --allow-empty -m "init"
for n in 1 2 3 4 5; do
  git worktree add -q -b "hermes/task-$n" "../task-$n"
done
git worktree list

git worktree list 会输出六行。第一行是 acme,手册称它为主 worktree:也就是由 git init 或 git clone 创建的那个。其余五个是关联 worktree。一个仓库拥有“一个主 worktree(如果不是裸仓库),以及零个或多个关联 worktree”(git-worktree)。

-b 会创建分支,并在新文件夹中检出它。如果省略 -b,git 会使用路径的最后一部分作为分支名,因此 git worktree add ../hotfix 会创建一个名为 hotfix 的分支(git-worktree)。

.git 也可以是一个文件

在 acme 中,.git 是一个目录。在 task-1 中,它却是一个只有一行内容的文本文件:

cd ../task-1
cat .git
git rev-parse --git-dir
git rev-parse --git-common-dir

这个文件包含 gitdir: 和一个路径。仓库布局文档把它称为 gitfile,submodule 用的也是同一种机制。它指向主仓库内部的一个私有目录:acme/.git/worktrees/task-1。这就是 --git-dir 输出的路径。--git-common-dir 输出的则是主仓库的 acme/.git。

因此,每个关联 worktree 都有两个 git 目录。Git 会根据所访问的路径,决定使用哪一个。看看私有目录里的内容:

ls ../acme/.git/worktrees/task-1
cat ../acme/.git/worktrees/task-1/commondir
cat ../acme/.git/worktrees/task-1/gitdir

你会看到这个 worktree 自己的 HEAD 和 index,以及两个链接文件。commondir 的内容是 ../..,这是从私有目录返回 acme/.git 的相对路径。git worktree add 写入的就是这个字符串(builtin/worktree.c)。gitdir 保存的则是指回 task-1/.git 的绝对路径,因此两边可以相互定位。Git 会利用这个反向链接,发现某个 worktree 文件夹是否已经被删除(gitrepository-layout)。

五个工作文件夹,底层共用一份存储。

One large vault labelled with a git branch symbol in the centre, with five small identical desks around it, each linked to the vault by a thin line

五个 Agent 共享什么,各自又拥有什么

手册给出的规则是:“所有伪引用都属于各自的 worktree,所有以 refs/ 开头的引用都共享。”例外是 refs/bisect、refs/worktree 和 refs/rewritten,它们仍然归各自的 worktree 所有(git-worktree)。在 task-1 中,让 git 告诉你这些路径分别会解析到哪里:

git rev-parse --git-path HEAD
git rev-parse --git-path refs/heads/main
git rev-parse --git-path objects

HEAD 会解析到 .git/worktrees/task-1 下。分支引用和 objects 则会解析到主仓库的 acme/.git 下。仓库布局文档还列出了其他只存放在公共目录中的内容,包括 config、hooks、packed-refs 和 info 等(gitrepository-layout)。

  • 各自的 HEAD,因此每个文件夹都有自己检出的分支。
  • 各自的 index,因此在一个文件夹中执行 git add,不会把另一个文件夹中的任何内容加入暂存区。
  • 各自的 refs/bisect,因此一个 Agent 可以执行二分查找,而不影响其他 Agent 的位置。
  • 各自在磁盘上的文件,包括被忽略的文件。这就是 .env 和 node_modules 不会跟着你进入新 worktree 的原因。

其余内容全部共享。在 task-1 中提交,然后在 task-2 中运行 git log -1 hermes/task-1:你会看到刚才的 commit,无须 fetch,因为这两个文件夹读取的是同一份引用和对象。stash 也遵循同样的规则。refs/stash 以 refs/ 开头,因此一个 Agent 在自己文件夹里存入的 stash,会出现在其他所有文件夹的 git stash list 中,而且任何一个 Agent 都可以将它 pop 出来。

config 和 hooks 也位于公共目录。默认情况下,config 文件是共享的(git-worktree),所以某个 Agent 在自己的 worktree 中运行 git config user.email,会修改所有 worktree 的配置。如果希望某项配置只对当前 worktree 生效,可以启用 extensions.worktreeConfig,再使用 git config --worktree。较旧的 git 版本会拒绝打开启用了这个扩展的仓库。hook 也是如此:同一个 pre-commit hook 会在每个 Agent 提交时运行。

一个分支只能对应一个 worktree

现在试着切换到另一个 Agent 正在使用的分支:

cd ../task-2
git switch hermes/task-1
git branch --list 'hermes/*'

切换会失败。这条消息来自 git 源码中的 die_if_checked_out,格式为 '%s' is already used by worktree at '%s'(branch.c)。较早的教程展示的是之前的措辞:“already checked out at”。Git 在 2023 年修改了它。对于已在关联 worktree 中检出的分支,git branch 会用 + 标记(git-branch)。

原因就在前面讲到的存储划分中。HEAD 和 index 属于各自的 worktree,但分支引用是共享的。如果两个 worktree 都检出了 hermes/task-1,那么在其中一个 worktree 中提交,就会移动另一个 worktree 所依赖的分支位置。这样,第二个文件夹里的文件和 index,就会与它的 HEAD 所指向的 commit 不再匹配。Git 会拒绝这种情况。git worktree add 同样会拒绝,除非你传入 --force。即使是 git branch -f,也不会移动一个已在另一个关联 worktree 中检出的分支(git-branch)。

在 Hermes 中,通过 ⌘N 启动的任务会获得一个新的 hermes/<name> 分支,因此这样启动的两个任务绝不会占用同一个分支。如果你想在主检出目录中切换到某个正在工作的 Agent 的分支,git 会先拦住你,避免你抽走它脚下的地板。

Hermes 的 worktree 隔离有一个边界:额外文件夹。从 2.3 开始,除了主项目,你还可以为一项 Claude 任务提供最多五个额外文件夹。只有主项目会获得该任务的新分支。额外文件夹会直接在原位置、原分支上被编辑(2.3.0 发布说明)。2.3.0 发布说明没有提到不同任务之间会对额外文件夹加锁,因此任务运行期间,应避免其他 Agent 操作这些文件夹。

用于跨仓库重命名的 ⌘N New task 面板:项目标签为“orders-api +2”,使用新的 hermes/ worktree,选择 Accept edits,通过“Also:”标签列出额外文件夹,并显示“Hermes will run”命令预览。

The New task sheet in Hermes 2.3 for a cross-repo rename, with a project chip reading orders-api +2, a new hermes/ worktree, Accept edits, the Also chips for the extra folders, and a preview of the command Hermes will run

lock、prune 和 repair:私有目录的生命周期

即使发生误操作,.git/worktrees 下的私有目录也可能继续保留。管理它的命令有三个。

prune。 手动删除一个 worktree 文件夹后,它的私有目录仍然会留下来:

cd ~/code/wt-lab/acme
rm -rf ../task-3
git worktree list --verbose
git worktree prune --dry-run --verbose
git worktree prune
git branch --list 'hermes/task-3'

list --verbose 会将这条记录标记为 prunable,并给出原因,例如“gitdir file points to non-existent location”(git-worktree)。prune 会删除私有目录,但不会动分支,因为分支位于共享引用中。因此,Agent 在 hermes/task-3 上提交的所有内容都会保留。被删除文件夹里尚未提交的工作则已经丢失。如果你一直不执行 prune,git gc 会代劳:它会调用 git worktree prune --expire 3.months.ago,而 gc.worktreePruneExpire 可以调整这个宽限期(git-gc)。下次请使用 git worktree remove:如果文件夹中存在已修改或未跟踪的文件,它会拒绝删除,除非你加上 --force。

lock。 存放在 USB 磁盘或网络共享位置上的 worktree,在未挂载时看起来就像被删除了一样。将它锁定后,prune 就不会清理它:

git worktree lock --reason "on usb disk" ../task-4
cat .git/worktrees/task-4/locked
git worktree unlock ../task-4

这个锁只是私有目录中一个名为 locked 的文件,里面以纯文本保存锁定原因。Git 在创建 worktree 时也会使用同一个文件:git worktree add 会在检出之前写入内容为“initializing”的 locked 文件,并在完成后删除它。这样,同时运行的 prune 就无法删除一个尚未创建完成的记录(builtin/worktree.c)。如果希望 worktree 从创建之初就一直保持锁定,可以使用 git worktree add --lock,它能“避免竞态条件”(git-worktree)。

repair。 两个链接文件都保存了路径,因此移动文件夹会破坏这些链接。使用 git worktree move 移动关联 worktree 时,git 会更新链接。如果直接用 mv 移动主仓库,关联 worktree 就再也找不到它了。在主 worktree 中运行 git worktree repair,即可重新连接它们(git-worktree):

cd ~/code/wt-lab
mv acme acme-moved
cd acme-moved && git worktree repair

这些链接默认使用绝对路径。Git 2.48 增加了相对路径支持,可以通过 git worktree add --relative-paths 或 worktree.useRelativePaths 启用(git-worktree),同时引入了一个仓库扩展,防止较旧的 git 版本误读这些链接(2.48.0 发布说明)。当仓库挂载在不同路径下时,例如分别在你的电脑上和容器内部,相对路径就能派上用场。repair --relative-paths 可以转换已有链接。

lock 保留私有目录,prune 清理私有目录,repair 重新连接它。

A small paper folder on a desk with a padlock on its tab, a broom leaning on one side and a wrench on the other, connected by a thin line to a large vault

Hermes 也会遇到同样的生命周期问题,它的发布说明记录了具体情况。在 2.2.9 中,关闭会话时选择保留的 worktree,不会再于之后被自动删除。如果某个 worktree 在会话关闭时未能移除,应用会在下次启动时重试。在独立 worktree 中运行的任务,其轮次历史快照会在会话关闭 14 天后从仓库中删除。我的理解是,最后这一点又回到了共享对象存储:无论哪个 worktree 写入了什么,最终都会进入它们共用的那一个 .git。

亲手运行一遍这个实验仓库,五个文件夹就不再神秘了。我开发的 Hermes IDE 会为你通过 ⌘N 启动的每项任务,自动创建独立的 hermes/<name> 分支和 worktree。它可以免费使用,以 BSL 1.1 许可开放源码,支持 macOS、Windows 和 Linux。下载试试吧,如果它帮你避免了一次检出目录混乱,也欢迎在 GitHub 上点个 star。

当五个 Agent 并行提交时,git 能告诉你改了什么,却无法告诉你每个 Agent 为此做过什么,以及消耗的 token 花了多少钱。LLM Observability Pocket Guide 是一本短书,介绍如何为团队选择能回答这些问题的 tracing 和 evals 工具。它是 Pocket Guides 系列 8 本短书中的一本,整个系列涵盖 Agent、RAG、prompt、可观测性、事件、数据库和系统设计。

LLM Observability Pocket Guide: Picking the Right Tracing & Evals Tools for Your Team

如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
用事件钩子识别编码智能体何时等待操作
下一篇
Copilot 部分模型将于11月16日退役