Anthropic 重设计源码管理的工程实践:从 git 迁移至 Scion
Redesigning source control at Anthropic
Anthropic 详解内部版本控制系统 Scion 的设计与迁移实践,以应对日均代码合并量从 2026 年 5 月约 2,500 次增至 9 月超过 30,000 次的负载。
将客户端始终在线作为设计前提,把历史查询与合并计算移至服务端,为应对智能体海量代码变更提供了可迁移的架构思路。
在 Anthropic,编写代码已不再是构建系统或开展研究的瓶颈。Claude 能够自主迭代研究循环、对复杂程序进行微优化,并以前所未见的速度和规模从零构建新服务。如今的瓶颈,是所有为人类工作规模打造的开发者基础设施:源代码管理、构建和 CI。
2026 年 5 月,Anthropic 平均每天合并约 2,500 项代码变更;截至 9 月,我们每天合并的代码变更已超过 30,000 项。我们预计,这一增长速度短期内不会放缓;合并代码的潜在需求几乎是无限的,每消除一个瓶颈,我们产出的代码量就会立即进一步增加。

2026 年 1 月至 9 月,我们的单体仓库每天合并的变更数量。
为支撑这一增长,我们构建了内部版本控制系统 Scion,并在五个月内将单体仓库从 git 完全迁移到了 Scion。在同一时期,我们还构建并上线了代码审查界面(名为 Antique)、代码搜索、功能丰富的源代码管理身份与访问管理(IAM)系统、用于管理和合入大量已审查代码的新方法等。本文将重点介绍我们具体是如何构建 Scion 的。这是一个有趣的案例:Claude 编写代码的能力,既是我们最初陷入这种局面的原因,也是我们能够快速构建高质量、可扩展系统来应对这一局面的关键。
不断扩大的单体仓库
在介绍我们构建的系统之前,我们应该先说明,我们的工作负载有多么不同寻常。不出所料,Anthropic 使用 Claude 编写软件的程度远超几乎所有其他公司,因此,我们往往最先发现那些为人类工作规模打造的工具从哪里开始不堪重负。源代码管理只是其中一个例子。虽然我们预计短期内不会有很多组织遇到这些问题,但我们认为,用不了多久,其他使用 AI 编程工具的组织也会遇到同样的压力点。这就是我们想分享所构建的系统和所学经验的原因。
Git 是一个去中心化系统:每个克隆都是一个完整、自包含的仓库,能够在完全离线的情况下计算差异、读取历史记录和逐行追溯信息,并检出任意修订版本。对于绝大多数仓库而言,这是恰当的设计,也是 git 成为标准的重要原因。
随着我们的单体仓库不断扩大,它越来越不适合这种设计。仅主分支的历史记录就接近 100 GB,而一份压缩后的工作副本也超过 25 GB。仅 CI 每天就要执行约 2,500 万次代码检出,这还不包括开发环境、智能体沙箱和研究任务。如果直接拉取这些代码,每天产生的 git 流量将超过 600 PB。
Git 提供了处理仓库局部内容的工具,例如浅克隆、稀疏检出和承诺远程仓库(promisor remotes)。此外,针对大型单体仓库,还有一些常规的变通方案,例如内部 git 镜像,以及保存在 Blob 存储中的仓库快照(种子)。这些方法我们全都用过——在高峰期,我们运行了数百个内部 git 镜像来应对负载。这为我们争取了时间,但随着合并速率提高,它们也变得越来越难以运维。在两次刷新之间,种子与主分支最新状态的差距越来越大;要让 diff 和 blame 等依赖历史记录的操作在部分克隆上正常运行,也需要越来越精心的维护。

扩展 git 检出规模的典型配置。
退一步看,我们注意到,与大多数公司一样,我们将 git 用作一个集中式系统,其中只有一份权威副本,但我们的客户端几乎全是智能体和作业,它们本身就始终在线。随着仓库不断增长,那些让 git 非常适合分布式、离线工作的特性,反而在削弱我们的扩展能力。于是我们问自己:如果从一开始设计源代码管理系统时,就考虑到智能体始终在线这一事实,它会是什么样子?
面向智能体规模的源代码管理原则
随着智能体编程的发展,许多关于软件开发方式的常见假设正在演变。我们在构建 Scion 时顺应了这些变化,从而得以在几项核心原则上采取与 git 根本不同的方式。面向超大型单体仓库的源代码管理已有先例,尤其是 Google 的 Piper 和 Meta 的 Sapling,2因此,我们在构建 Scion 时能够借鉴它们来之不易的经验。我们的原则如下:
客户端始终在线。Git 假设客户端离线工作,需要一份完整的仓库副本。由于我们的客户端几乎全是智能体和作业,我们围绕始终可访问的服务器来设计 Scion 的客户端和协议,让客户端在需要时获取数据。
客户端与服务器不对称。在 git 中,每个客户端都能够充当功能完备的服务器。在 Scion 中,服务器负责回答有关文件历史和逐行追溯的问题、创建提交、执行合并与变基等操作。客户端则维护一个大小受限的本地对象缓存,将工作副本文件写入磁盘,监控文件系统变化,并为用户提供便捷的服务器交互方式。它自身能完成的计算很少,但作为交换,本地所需的数据也少得多。
全面的源代码管理服务可以支撑许多新型应用。使用 git 时,如果 CI 作业或工具需要查询仓库信息,例如谁最后修改了某一行,或两次提交之间有何关系,就必须维护一份本地仓库副本,或者寄希望于特定供应商的 API 能提供答案。在 Scion 中,客户端使用的所有源代码管理查询也都通过 API 开放,因此在很多情况下,作业根本不需要本地仓库。如果没有这种低成本、可编程的源代码管理访问方式,许多内部工具,例如我们的自动二分查找和回退流水线,就无法在大规模场景下切实运行。
一切都必须能够水平扩展。在高峰期,我们运行了数百个 git 镜像,这给容量带来了巨大压力,而且一旦仓库大小超出镜像的磁盘或内存限制,就无法继续扩展。在 Scion 中,仓库数据采用分布式存储,每个组件都可以独立扩展;任何地方都没有完整落地的仓库副本,即使在服务器上也是如此。系统中没有与 packfiles(git 的压缩对象包)对应的结构,因此无需进行仓库维护。
提交必须开销低、采用增量方式且无锁。在 git 中,你先在本地提交,再通过推送来共享工作成果。在 Scion 中,每次提交、变基或合并都在服务器上进行,因此无需推送,但这些操作都必须足够快。创建提交及更新其下游数据结构的开销必须随变更规模而非整个代码库的规模增长,否则服务器就无法跟上。Scion 的开发生命周期不鼓励使用引用(指向提交的指针,例如分支和标签),主引用或发布分支除外,因为需要所有服务器达成一致的全局状态是一个潜在的扩展性问题。
工作副本是可选的,而且从设计上就是稀疏的。由于我们的单体代码库非常庞大,而且每天要为 CI 检出代码数千万次,因此我们希望尽可能避免检出。例如,使用 Scion 时,如果某个 CI 作业需要获取某次提交与其合并基点之间的差异,就可以向服务器请求。写入也是如此:许多写入工作负载同样可以跳过检出,完全通过 API 完成操作。Scion 的协议以稀疏检出和虚拟化检出为核心:前者只包含客户端请求的目录,后者则按需将文件实体化,因此,当作业确实需要磁盘上的文件时,客户端只需为实际读取的内容付出开销。
Scion 的工作原理
了解构建 Scion 时这些原则如何在实践中结合起来,会很有帮助。这些心得也适用于其他源代码管理系统,或者更广泛地说,适用于软件开发生命周期的其他阶段。
数据结构
在 Scion 中,工作单元是“变更集”,即预写日志中的一个条目。变更集存储了你预期 git 提交会包含的大部分内容。但 git 提交存储的是指向树的指针,而变更集存储的是相对于其第一个父提交发生变更的文件列表,1以及指向 blob 存储中压缩文件内容的内容寻址指针。变更集在服务器端创建,并立即在所有位置可用。

Scion 中变更集的结构。
这种结构让我们能够以极高的吞吐量接收变更集,因为没有需要接收的打包文件,不需要加锁或跨服务器协调,也没有需要移动的引用。Scion 在技术上确实支持引用,但由于创建和获取提交都不涉及引用,因此移动引用只是对 Spanner 中单行执行的一次比较并交换操作,与创建变更集分开进行。
变更集只记录发生了哪些变更,因此仅凭它本身,无法快速回答谁最后编辑了某一行,或哪些提交影响了某个文件之类的问题。为回答这些问题,Scion 会根据变更集构建额外的数据结构,包括用于文件逐行追溯和路径历史的专用结构,以及用于提交图的跳表。我们将所有不直接属于变更集的内容称为“派生数据”,并通过同一种通用机制计算所有这些数据。每种派生数据都以递归方式定义,因此,某个变更集的派生数据值是根据其父变更集的对应值计算得出的。
这种机制有三个好处。首先,当一种新的数据结构可以加快某项操作时,我们可以轻松添加一种新的派生数据类型。其次,对于每种类型,我们都可以选择立即计算还是延后处理,从而避免将不需要的数据物化。第三,由于客户端永远看不到这些数据结构的内部实现,我们可以在不更改客户端的情况下对其进行优化。随着系统的发展,我们已经多次添加新的派生数据类型,例如用于执行复制检测或基于路径的文件搜索的新索引。
扩展 Scion
一小组 Scion 服务器提供源代码管理 API,支持客户端所需的任何操作,例如获取变更集、计算差异、查找合并基点和获取 blob。所有源代码管理数据都采用内容寻址,因此一份数据一旦存储就不会再改变,任何服务器都可以缓存它,而无须与其他服务器核实。因此,这些服务器可以水平扩展,且几乎不需要协调。它们本质上是大型缓存,同时也能即时计算派生数据,并将结果写回 Spanner。
Scion 的众多使用方不再需要维护各自的本地仓库。对于需要查询源代码管理信息的 CI 任务或工具而言,获取和维护仓库过去是一项沉重的维护负担,尤其是在查询提交祖先关系和逐行追溯信息时。在迁移初期,我们还没有自己的客户端、仓库格式或协议,Scion 当时只回答这些“元数据”查询。获取文件内容和物化工作副本的数据量要大得多,因此需要专门的设计。
Scion 的 scn 客户端在几个重要方面不同于 git 的获取协议,因此适合采用高度可扩展的架构,其 CPU 需求显著低于 git 服务器。Scion 的协商过程不会告诉服务器客户端已经拥有什么,而是只针对客户端需要的树和 blob 进行操作。从根树开始,客户端检查本地存储中缺失的树,并递归请求这些树,然后对 blob 重复这一过程。每个请求都针对一个永远不会改变的特定对象,因此任何缓存都可以响应,整个架构与传统的分层缓存非常相似。由于不存在单个数 GB 的 packfile 响应,这一过程也很高效,并且可以断点续传。稀疏检出乃至虚拟化检出都不需要特殊支持,因为客户端根本不会请求它不需要的树。
在集群中,客户端通过套接字与守护进程 scion-daemon 通信,该进程为整个节点存储对象。我们的大多数节点都需要访问单体仓库,同一节点上的任务会复用大部分相同的对象。每个守护进程都从定期刷新的快照开始运行,之后只与所在区域中称为 scion-cache 的树和 blob 缓存服务器通信。这些缓存服务器直接从内存中以流式方式传输对象,使用的就是守护进程将要读取的磁盘格式,因此无须花时间计算客户端缺失的对象或执行增量压缩。当缓存缺少某个对象时,它会向权威的 scion-servers 请求,后者会根据需要从 Spanner 或云存储中读取。
scion-daemon、scion-cache 和 scion-server 都会响应此协议中相同的 RPC,因此客户端无需了解缓存拓扑。理论上,任何一层都可以与其他任何一层通信,但我们严格执行分层规则,以隔离故障域。我们希望避免区域级 scion-cache 发生故障后,导致上游 scion-server 不堪重负,进而使整个系统瘫痪。

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、速度提升至原来 4 倍的版本,同时保留了摄取顺序和数据结构方面的所有隐含不变量。

2026 年 1 月至 9 月,Scion 和 Antique 代码库每周合并的变更。
我们在构建和运行 Scion 过程中积累的经验,为面向智能体规模的软件开发可能呈现的形态提供了一些有趣的启示。
小团队快速开发将变得更加普遍。一个七人团队在五个月内构建了 Scion 和 Antique(我们的代码审查工具,关于它,我们完全可以另写一整篇博客文章),以及六个相关系统,并全面完成了向这些系统的迁移。我们完成所有这些工作的同时,每天合并的代码量还增长到了原来的 10 倍。过去,开发和部署这样一个源代码管理系统,需要一家公司投入更多工程师,经过多年的迭代迁移才能完成。我们认为,这种快速、灵活的迁移未来会变得更加普遍。
工程师的价值丝毫未减,但他们的工作正在改变。参与这个系统开发的所有工程师如今都认为,Claude 在编写代码方面比自己更出色。但我们的工程师仍然提供了不可或缺的理解:他们了解系统间组件的高层结构以及设计层面的权衡,能够围绕我们想要解决的问题和我们明确需要达到的规模,作出明智的选择。我们经常发现,工程师的职责是对 Claude 说“不”。智能体有时会违反系统的核心约束,以满足一种本就不该被允许的模式。这在我们的迁移过程中尤为常见。例如,有多个系统试图通过线性读取提交日志,以蛮力方式查找某项变更何时合并到 main,而不是查询我们的代码审查工具。Anthropic 还广泛采用对抗性审查,虽然这种方法在很多方面极为有效,但也可能目光短浅,因此需要经验丰富的工程师引导 Claude,避免它为了应对假设性问题而对系统的某些部分进行过度设计。例如,有一次这样的审查对于信任另一个内部服务过于谨慎,导致 Claude 添加了过多的验证和复杂性。我们的团队成员仍然会审查系统的每个变更请求,但他们现在检查的是变更的意图,而不再逐行阅读代码。
我们得以大幅提升优化程度和质量。得益于 Claude 能够以远超我们自身的速度编写海量代码,Scion 成为我们参与过的测试最充分、防护最完善的代码库之一。即使时间紧迫,我们仍为以往遇到的每一种非简单的基础设施和源码管理交互构建了封闭隔离的模拟环境,并加入了模糊测试和精细的限流机制。Claude 还轻而易举地发现了显著的优化机会——例如,针对未利用到我们某个索引的祖先查询进行算法优化——这些原本需要专家花费数天乃至数周来分析和调优……而它第二天又完成了同样一轮工作。

在原生 Scion 仓库上观察到的性能提升。
我们为新形式的单体仓库安全机制奠定了基础。在庞大的单体仓库中,管理安全性、信息安全和合规性,与管理其大小和规模同样重要。我们从一开始构建 Scion 时就考虑到了这些需求。它支持丰富的仓库访问控制,还能对单个目录设置权限,从而在不失去单体仓库优势的情况下保护最敏感的代码。此外,我们构建的代码审查工具能够表达针对审批的复杂语义约束,让我们可以区分仅修改注释之类的简单变更与敏感的逻辑变更,使人工审查者能够专注于影响最重大的变更。
实现更高水平的卓越运维已成为可能。 我们的团队大量使用 Claude Tag,它帮助我们监控系统的每个组件。例如,我们创建了一些 Slack 频道,让 Claude 专注于单个组件的健康状况,做到近乎痴迷。我们把这些 Claude 称为“超级粉丝”。我们有 scion-daemon 的超级粉丝、scion-cache 的超级粉丝、Antique 合并队列的超级粉丝,等等。它们可以访问我们的遥测数据和日志,就像一位经验丰富的工程师,除了刷新图表、查找任何异常之外,别无他事可做。我们也为所有系统设置了传统告警,但这些超级粉丝能发现细微的新型问题,相比之下,传统告警就显得十分单一。
我们正在彻底重新审视原有假设。 这个项目促使我们非常认真地审视其他按人类工作规模设计的工作流。例如,在智能体规模下,一个规范的合并队列就不太有意义了。当测试运行期间可能有数百甚至数千项变更被合并时,CI 究竟意味着什么?我们一直未能有效复现行业标准做法,即在合并队列上对整个代码仓库施加全局锁,因此转而投入合并后、部署前的自动化测试。这确实意味着并发变更可能发生冲突,但 Claude 通常能在人工发现这些冲突之前就将其修复。
为更广泛的生态系统作贡献
随着 AI 智能体的能力日益增强,其引发的规模扩展问题也越来越受关注。我们认为,Scion 只是应对这些问题的答案之一。我们分享这些细节,是想展示团队可以如何应对类似挑战,但我们并不指望自己的解决方案或考量适用于所有情况。
Scion 绝不是适合通用场景的 git 替代品。我们在这里概述的概念,实际上只对真正庞大的单体代码仓库才有意义,这类仓库要么有数万名工程师参与,要么有大批智能体不断编写大量代码。此外,Anthropic 的独特之处在于,我们能够在内部使用上投入的 token 数量,远超其他任何企业在现实中愿意投入的水平。我们这样做,既是为了满足自身的软件开发需求,也是为了测试 Claude 的能力。
从实际角度来说,很难以一种对其他组织普遍有用的形式提供 Scion。它与 git 差异显著,这意味着企业需要迁移开发生命周期中的每一个环节,而且它需要专用的代码审查、代码搜索和 CI。我们内部的这些组件都是高度定制的,因此其他组织很难采用;我们也担心,尝试构建一个力图满足所有人需求的公开版本,实际上并不会很有用。
不过,我们预计,在接下来的六到12个月里,这类问题会变得更加普遍,而让每家使用 git 的公司都独自应对类似挑战,并不能高效利用工程资源。有鉴于此,我们认为,我们能做的最有影响力的 事情就是分享我们的思路,让其他开发者能够在不偏离整体模型的前提下,将 Scion 中一些最成功的部分应用到 git 中。git 服务器不必以与 git 客户端相同的方式工作;已有一些新型服务器架构能够显著提升扩展能力。Git 平台可以像 Scion 一样提供全面的服务器端 RPC,甚至可以在不同代码托管平台之间采用标准化方式,让 git 客户端能够学会与之通信。协商协议也不必与今天的样子完全一致,而且 git 中的各种稀疏和浅层功能也可以实现良好的组合使用。
最后,我们想肯定 git 社区近二十年来为扩展该平台、服务数百万开发者所付出的努力。我们的贡献要有限得多:分享我们对智能体软件开发如何与这些系统交互的初步认识,以便与 GitHub、GitLab 和开源社区携手,满足开发者不断变化的需求。当软件开发生命周期与 AI 的指数级发展交汇时,我们都置身其中,携手同行。
来源:Anthropic Engineering · anthropic.com