Git遇上大模型(3):Anthropic如何扩展Git

原文:Redesigning source control at Anthropic
作者:Anthropic
发布日期:2026 年 10 月 13 日;原文于 10 月 15 日更新
本文为中文翻译,图表来自原文

原文于 10 月 15 日更新,补充了更多关于率先采用 Scion 所用技术的项目的介绍。

在 Anthropic,编写代码已不再是构建系统或开展研究的瓶颈。Claude 能以前所未有的速度和规模,自主迭代研究流程、对复杂程序进行微观优化,并从零构建新服务。如今的瓶颈是那些按人类工作规模设计的开发基础设施:源码控制、构建和 CI。

2026 年 5 月,Anthropic 平均每天合入约 2,500 项代码改动;到 9 月,每天合入量已超过 30,000 项。我们预计这种增长不会很快放缓:等待合入的代码需求几乎无穷无尽,每消除一个瓶颈,代码产出就会立即进一步增加。

02-daily-merges

 

 

2026 年 1 月至 9 月,单体仓库每天合入的改动数。

为支撑这种增长,我们构建了内部版本控制系统 Scion,并在五个月内将单体仓库完全从 Git 迁移过去。同期,我们还开发并交付了名为 Antique 的代码审查界面、代码搜索、完善的源码控制身份与访问管理系统,以及管理和合入大量已审查代码的新方法。本文重点介绍 Scion 的构建过程。这是一个有趣的案例:Claude 的代码编写能力既让我们遇到了眼前的问题,也帮助我们迅速构建出高质量、可扩展的系统来应对问题。

不断增长的单体仓库

在介绍我们构建了什么之前,先承认我们工作负载的特殊性。Anthropic 使用 Claude 编写软件的程度远高于大多数公司,因此,我们经常最先发现为人类规模设计的工具开始吃力。源码控制只是其中一个例子。我们不认为许多组织会立刻遇到同样问题,但使用 AI 编程工具的团队恐怕不久后也会感受到这些压力。这正是我们分享构建过程和经验的原因。

Git 是一个去中心化系统:每份克隆都是完整、自足的仓库,即使完全离线,也能计算差异、查看历史与逐行追溯,并检出任何版本。对绝大多数仓库来说,这是正确的设计,也是 Git 成为标准的重要原因。

但随着单体仓库增长,它越来越不适合这种模式。仅主分支历史就接近 100 GB,压缩后的工作副本也超过 25 GB。仅 CI 每天就要检出约 2,500 万次代码,还不包括开发者环境、智能体沙盒和研究任务。如果采用朴素的拉取方式,每天会产生超过 600 PB 的 Git 流量。

Git 提供了只处理部分仓库的工具,例如浅克隆、稀疏检出和 promisor remote。此外,大型单体仓库还有一些常见变通方案,如内部 Git 镜像,以及存放在 blob 存储中的仓库快照(seed)。这些办法我们都用过。高峰时,我们运行了数百个内部 Git 镜像来分担负载。它们为我们争取了时间,但随着合入速度提高,运维越来越困难;两次刷新之间,seed 距离主分支最新端点越来越远;对于部分克隆,维护 diff 和 blame 这类依赖历史的操作,也需要越来越多的额外工作。

03-git-checkout-architecture

 

扩展 Git 检出能力的典型架构。

退一步看,我们发现自己和多数公司一样,实际上把 Git 当作只有一份权威副本的集中式系统使用;而几乎所有客户端都是天然在线的智能体和任务。Git 为分布式离线工作提供的特性,在仓库增长时反而妨碍了扩展。于是我们问自己:如果从一开始就以“智能体始终在线”为前提设计源码控制系统,它会是什么样?

面向智能体规模的源码控制原则

智能体编程正在改变许多关于软件开发的常见假设。构建 Scion 时,我们顺应这些变化,在几个核心原则上采用了与 Git 根本不同的方式。巨型单体仓库的源码控制并非没有先例,尤其是 Google 的 Piper 和 Meta 的 Sapling。2 我们得以汲取它们来之不易的经验。我们的原则如下。

客户端始终在线。 Git 假设客户端需要离线工作,因此必须拥有仓库的完整副本。由于我们的客户端几乎都是智能体和任务,Scion 的客户端和协议围绕始终可访问的服务器设计,只在需要时获取数据。

客户端与服务器职责不对称。 在 Git 中,每个客户端都有能力成为完整的服务器。在 Scion 中,服务器负责回答文件历史与 blame 问题、创建提交、执行合并和变基等。客户端保有有界的本地对象缓存,把工作副本文件放到磁盘上,监测文件系统变化,并提供方便用户与服务器协作的操作方式。它独立计算的能力很有限,换来的是本地需要的数据量小得多。

完整的源码控制服务可以支撑许多新应用。 使用 Git 时,CI 任务或工具若想查询谁最后改动了某一行、两个提交有何关系,就必须维护本地仓库副本,或者寄望于平台专有 API 给出答案。Scion 把客户端使用的所有源码控制查询都开放为 API,因此许多任务完全不需要本地仓库。我们的自动二分定位和回滚流水线等内部工具,如果没有这种廉价的程序化查询能力,就无法在此规模下实用运行。

所有部分都必须能够横向扩展。 高峰时期,我们运行数百个 Git 镜像,显著消耗了资源;一旦仓库超过镜像的磁盘或内存限制,它们也无法继续扩展。Scion 的仓库数据是分布式的,每个组件都能独立扩展;系统中没有任何一处保存完整物化的仓库副本,服务器上也没有。它没有与 packfile(Git 的压缩对象包)对应的结构,因此也无须执行仓库维护。

提交必须廉价、增量完成,而且不依赖锁。 在 Git 中,先在本地提交,再通过推送分享改动。在 Scion 中,每次提交、变基和合并都在服务器上完成,因此没有需要推送的内容,但这些操作都必须足够快。创建提交和更新其下游数据结构的成本,必须随改动规模而非整个仓库规模增长,否则服务器无法跟上。Scion 的开发流程尽量少用 ref(指向提交的分支、标签等),主 ref 或发布分支除外,因为需要所有服务器达成一致的全局状态,是潜在的扩展难题。

工作副本可选,且天生稀疏。 单体仓库非常大,CI 每天又要检出数千万次代码,因此我们希望能免则免。例如,CI 任务需要计算某个提交与其合并基点的差异,可以直接向服务器查询。写入也一样:许多工作负载无需检出,通过 API 就能完成。Scion 协议以稀疏检出和虚拟化检出为中心;前者只包含客户端请求的目录,后者按需物化文件。所以任务确实需要磁盘文件时,客户端只为实际读取的内容付费。

Scion 如何工作

了解这些原则如何在 Scion 的构建中落地很有帮助。这些经验也适用于其他源码控制系统,乃至软件开发生命周期的其他阶段。

数据结构

Scion 的工作单位是“变更集”(changeset),即预写日志中的一条记录。它保存了 Git 提交通常包含的大部分信息。不同的是,Git 提交保存指向文件树的指针,而变更集保存相对于第一个父提交发生变化的文件列表,1以及指向 blob 存储中压缩文件内容的、按内容寻址的指针。变更集在服务端创建,随后立即在各处可用。

04-scion-data-model

 

Scion 中变更集的结构。

这一结构使我们能以很高吞吐量接收变更集,因为不必接收 packfile,不需要锁或跨服务器协调,也没有必须移动的 ref。严格说来,Scion 支持 ref,但创建和获取提交都不依赖它。因此,移动 ref 只是对 Spanner 中单行数据执行一次比较并交换操作,与创建变更集分开进行。

变更集只记录发生了什么变化,单靠它无法快速回答“谁最后改动了这一行”或“哪些提交影响了这个文件”之类的问题。为此,Scion 从变更集构建额外数据结构,包括专用的逐行追溯和路径历史结构,以及提交图的跳表。我们把不直接属于变更集的内容统称为“派生数据”,通过一种通用机制计算它们。每种派生数据都按递归方式定义:某变更集的值,根据它的父变更集对应的值计算。

这一机制有三个好处。第一,当新数据结构能加快某项操作时,很容易加入一种新的派生数据。第二,对每种数据可以分别决定立即计算还是延后处理,从而避免物化不需要的数据。第三,客户端看不到这些数据结构的内部实现,因此可以不修改客户端就进行优化。随着系统发展,我们多次添加新的派生数据,例如用于检测文件复制或按路径搜索文件的新索引。

扩展 Scion

一小组 Scion 服务器提供客户端所需的源码控制 API,包括获取变更集、计算差异、寻找合并基点和取得 blob。所有源码控制数据都按内容寻址,存入后就不会改变,因此任意服务器都能缓存,而不必向其他服务器确认。由此,服务器可以横向扩展,所需协调很少。它们基本上是大型缓存,同时还能即时计算派生数据,并把结果写回 Spanner。

Scion 的众多使用方不再需要各自维护本地仓库。过去,CI 任务或其他工具若要查询源码控制信息,尤其是提交祖先关系和逐行追溯,获取并维护仓库是一项沉重的负担。迁移初期,我们甚至还没有自己的客户端、仓库格式或协议,Scion 只负责回答这类“元数据”查询。获取文件内容和物化工作副本的数据密集程度高得多,需要单独设计。

Scion 的 scn 客户端在几个关键方面不同于 Git 的拉取协议,因此能采用 CPU 消耗显著低于 Git 服务器的高扩展架构。Scion 的协商过程不会告诉服务器客户端已经拥有什么;它只处理客户端想要的 tree 和 blob。客户端从根 tree 开始,检查本地存储缺少哪些 tree,递归请求它们,再对 blob 重复同样过程。每次请求都指向一个永不变化的特定对象,因此任何缓存都能回答,整个架构与传统分层缓存非常相似。由于不存在单个数 GB 的 packfile 响应,过程也高效且可恢复。稀疏检出乃至虚拟化检出不需要特殊协议支持:客户端只需不请求那些不想要的 tree。

在计算集群中,客户端通过套接字与 scion-daemon 通信;这个守护进程为整台节点存储对象。我们大多数节点都需要访问单体仓库,而同一节点上的任务会复用大部分对象。每个守护进程从定期刷新的快照启动,随后只与本区域名为 scion-cache 的 tree 和 blob 缓存服务器通信。这些缓存服务器直接从内存流式输出对象,使用守护进程要消费的磁盘格式,因此无须花时间计算客户端缺少哪些对象,也无须进行增量压缩。缓存缺失对象时,就向权威的 scion-server 请求;后者按需从 Spanner 或云存储读取。

scion-daemon、scion-cache 和 scion-server 都通过相同的 RPC 响应该协议,因此客户端不必了解缓存拓扑。理论上任意层级都能与其他层级通信,但我们严格执行分层,以隔离故障域。我们不希望区域性 scion-cache 故障把上游 scion-server 压垮,进而拖垮整个系统。

05-scion-cache-architecture

 

Scion 的检出架构。

这一系统的每一层缓存命中率都超过 99%,且不依赖长期保存的状态,因此需要时很容易扩容。按 CPU 和内存需求衡量,Scion 的基础设施规模如今只有此前 Git 镜像设施的 1/200。CI 和研究任务检出代码的速度提高了两个数量级:从数分钟缩短到数秒。这释放了计算集群的大量容量;仅 CI 就节省了 25% 的 CPU 容量。客户端和缓存均无须执行仓库维护,也简化了任务的生命周期管理。

构建 Scion 的经验

我们开始构建 Scion 的时间,恰好与 Claude Mythos Preview 和 Claude Tag 在内部可用的时间接近。这两个版本既放大了对 Scion 的需求,也显著加快了建设速度。

有个例子特别鲜明。今年早些时候,我们基本靠人工写出了 Git 到 Scion 数据导入流水线的第一个原型,自以为效果不错。后来拿到 Claude Mythos Preview 的早期内部快照,请它重写整个系统,没有再给任何额外指示。结果,它写出的版本在保留导入顺序和数据结构全部隐含不变量的同时,内存消耗降低到原来的 1/20,速度提高了四倍。

06-scion-antique-merges

 

2026 年 1 月至 9 月,Scion 与 Antique 代码库每周合入的改动数。

构建和运行 Scion 的过程,让我们对智能体规模的软件开发有了一些有趣的认识。

小团队快速开发将更常见。 七人团队构建了 Scion 和代码审查工具 Antique,另外还开发了约半打相关系统,并在五个月内完成全面迁移。与此同时,每天合入的代码量增长了十倍。过去,要开发并部署这样的源码控制系统,一家公司可能需要更多工程师,花数年时间逐步迁移。我们认为,未来这种快速、灵活的迁移会越来越常见。

工程师并没有变得不重要,但工作内容正在改变。 参与该系统的所有工程师如今都认为,Claude 写代码的能力超过了自己。但工程师依然提供不可替代的系统级理解和设计取舍能力,能够依据要解决的问题及所需规模作出明智选择。我们发现,工程师的工作经常是对 Claude 说“不”。智能体有时会为了满足某种模式而违反系统核心约束,而这种模式本来就不该被允许。迁移中尤其常见。比如,多个系统试图线性读取提交日志,用蛮力查找某项改动何时合入主分支,而不是查询代码审查工具。Anthropic 还广泛采用对抗性审查;它在许多方面非常有效,但有时也会视野狭窄。因此,经验丰富的工程师需要引导 Claude,避免它为假设性担忧而过度设计。例如,一次审查对信任另一内部服务过于保守,导致 Claude 添加了过多验证和复杂性。团队成员仍会审查系统的每一项变更请求,但现在关注的是改动意图,而不是逐行阅读全部代码。

我们显著提高了优化水平和质量。 Claude 能远比我们更快地编写大量代码,因此 Scion 成了我们参与过的测试最充分、防护最完善的代码库之一。即使时间紧迫,我们仍能针对遇到过的每一种非平凡基础设施和源码控制交互建立隔离、可重复的模拟,还加入了模糊测试和精细的限流。Claude 也顺手发现了重大优化机会。例如,有一次它发现祖先关系查询遗漏了一个索引,并提出算法优化;专家可能需要数天甚至数周才能完成相同的分析和调优,而它第二天又能继续做类似的事。

07-scion-performance

 

原生 Scion 仓库中观测到的性能提升。

我们为新形式的单体仓库安全机制打下了基础。 对庞大的单体仓库而言,安全、保密和合规的重要性,与管理规模和负载一样高。构建 Scion 时,我们从一开始就考虑了这些问题。它支持丰富的仓库访问控制,还能对单个目录施加权限,以便保护最敏感的代码,同时保留单体仓库的好处。此外,我们构建的代码审查工具可以表达复杂的审批语义约束,区分只改注释等简单变更与敏感的逻辑变更,让人工审查者专注于影响最大的改动。

更高水平的运维质量成为可能。 团队大量使用 Claude Tag 来监控系统的每个组件。例如,我们建立了若干 Slack 频道,让 Claude 专注盯守单个组件的健康状况,并称它们为“超级粉丝”。我们有 scion-daemon 超级粉丝、scion-cache 超级粉丝、Antique 合并队列超级粉丝,等等。它们可以访问遥测数据和日志,就像一位别无他事、只管不断刷新图表寻找异常的资深工程师。系统当然也有传统告警,但与超级粉丝能发现的细微、新型问题相比,这些告警显得较为单一。

我们正在重新审视先前的假设。 这个项目促使我们认真审视其他为人类规模设计的工作流。例如,在智能体规模下,传统意义上的合并队列未必合理。当测试运行期间就可能合入数百甚至数千项改动,CI 究竟意味着什么?我们无法有效复制业界常见的“用全局仓库锁保护合并队列”的做法,因此转向投资合并后和部署前的自动化测试。这确实意味着并发改动可能发生冲突,但 Claude 通常能在人类辨认出冲突之前就把它修好。

为更广泛的生态作贡献

我们认为,Scion 只是应对越来越强大的 AI 智能体带来的扩展问题的一部分答案。分享这些细节,是为了展示团队可以如何处理类似挑战;我们并不期待自己的方案或考虑适用于所有情况。

Scion 绝不是适用于一般用途的 Git 替代品。这里介绍的理念,实际上只适合真正庞大的单体仓库:要么有数万名工程师,要么有大批高产的智能体。此外,Anthropic 的情况很特殊:我们能为内部用途消耗的 token,远超其他企业在现实中愿意承担的水平。这样做既是为了满足自身的软件开发需求,也是为了测试 Claude 的能力。

从实践角度看,很难把 Scion 作为可广泛供其他组织使用的产品提供。它与 Git 差异很大,企业必须迁移开发生命周期的每个环节;它还需要配套的代码审查、代码搜索和 CI。我们内部使用的这些组件高度定制,其他组织很难直接采用。我们也担心,试图构建一个满足所有人需求的公开版本,最终可能并不实用。

不过,我们预计接下来六到十二个月,这类问题会越来越普遍。让每一家使用 Git 的公司独自面对相似挑战,是对工程资源的低效使用。因此,我们认为最有价值的做法是分享思路,让其他开发者在不脱离 Git 整体模型的情况下,将 Scion 中最成功的部分应用于 Git。Git 服务器不必与 Git 客户端采用相同的工作方式;新的服务器架构可以显著提升扩展能力。Git 平台可以像 Scion 一样提供完整的服务端 RPC,甚至可以让不同代码托管平台以标准化方式提供,使 Git 客户端能够与之通信。协商协议也不必完全保持现在的样子;Git 中各种稀疏和浅克隆功能,可以设计得更容易组合使用。

最后,我们想感谢 Git 社区近二十年来为数百万开发者扩展这一平台所做的工作。我们的贡献要窄得多:分享我们对智能体软件开发如何与这些系统相互作用的早期观察,以便与 GitHub、GitLab 和开源社区合作,支持开发者不断变化的需求。当软件开发生命周期与 AI 的指数级发展交汇时,我们都在同一条船上。

posted @ 2026-11-03 14:32  ffl  阅读(11)  评论(0)    收藏  举报