7个人、5个月,Anthropic造出了Git替代品

Anthropic用5个月自主研发了源代码控制系统Scion,替换了其内部使用多年的Git。

文章作者、来源:机器之心

Git,这个统治程序员20年的版本控制工具,竟然被Anthropic自己造的新系统替换了。

而完成这一切的,只有7名工程师和深度参与开发的Claude。

5个月,Anthropic从零开发出了内部源代码控制系统Scion、配套的代码审查工具Antique以及其他多个相关系统,并完成了整个单体代码仓库从Git到Scion的迁移。

Monorepo

这意味着什么?几个人借助AI,仅需要数月,就造出一套新系统,把自家内部用了多年的Git直接换掉了。简直太夸张了!这就不由得有人发出了「RIP GIT」的感叹。

Monorepo

为什么要自己造一套Git替代品?

原因很简单,Anthropic的AI编程规模已经大到原有开发基础设施快撑不住了。

Anthropic给出的数据显示,今年5月,其平均每天合并约2500次代码变更。到了9月,这个数字已经突破3万次,短短4个月增长了12倍以上。并且,Anthropic预计,这种增长短期内不会放缓。代码合并的潜在需求几乎没有上限,每当解决一个瓶颈,代码产出量就会进一步增加。

Monorepo

在现实的倒逼下,Anthropic开发了内部版本控制系统,并在五个月内将整个Monorepo(单体代码仓库)从Git完整迁移到Scion。

Anthropic在最新的博客中完整介绍了整个流程。

一、不断膨胀的Monorepo

在介绍Scion之前,有必要先说明Anthropic的工作负载有多特殊。其使用Claude编写软件的程度,远远超过绝大多数公司。其中,那些为人类开发规模设计的工具在哪些地方开始吃力。源代码控制只是其中一个例子。

Anthropic预计,短期内不会有太多公司遇到同样的问题。但随着AI编程工具越来越普及,其他公司应该也用不了多久就会碰到类似的瓶颈。这也是我们决定分享Scion的设计和开发经验的原因。

Git是一个去中心化系统。每次克隆都会得到一份完整、独立的代码仓库。即使完全离线,开发者也能计算代码差异、查看提交历史、追踪某一行代码的修改记录以及检出任意版本。对绝大多数代码仓库来说,这套设计非常合理,也是Git成为行业标准的重要原因。

但随着Anthropic的Monorepo不断增长,Git的设计越来越难以满足需求。目前,仅主分支的历史数据就接近100GB,压缩后的工作副本也超过25GB。仅CI系统每天就要执行约2500万次代码检出,还没有算上开发环境、Agent沙箱和研究任务。如果每次都直接从Git获取所需数据,每天产生的数据传输量将超过600PB。

Monorepo

Git当然也提供了处理部分仓库数据的功能,例如浅克隆、稀疏检出和Promisor Remote。业界也有一些应对大型Monorepo的常见办法,比如搭建内部Git镜像,或者把代码仓库快照保存在对象存储中。

这些方法Anthropic全用过。在负载最高的时候,甚至运行着几百台内部Git镜像服务器。这些方案确实帮助撑了一段时间。但随着代码合并量不断增长,它们也越来越难维护。两次快照刷新之间,快照与主分支最新版本的差距会越来越大。同时,要让部分克隆的仓库正常执行diff、blame等依赖历史信息的操作,也需要投入越来越多的维护工作。

Monorepo

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

后来,Anthropic重新审视了自己的使用方式,发现了一个问题。和大多数公司一样,Anthropic实际上一直把Git当作集中式系统使用,所有开发工作都围绕一份权威代码仓库展开。但客户端几乎都是Agent和自动化任务,它们本来就始终在线。Git为分布式和离线开发提供的那些特性,反而在代码仓库不断增长时限制了系统的扩展能力。

于是,Anthropic开始思考:如果从一开始就按照Agent始终在线的特点设计源代码控制系统,它应该是什么样子?

二、面向Agent规模的源代码控制

随着Agent开始大量编写代码,软件开发中的许多传统假设正在发生变化。Anthropic在设计Scion时,充分考虑了这些变化,因此在几个核心原则上采取了与Git不同的方案。当然,超大型Monorepo的源代码控制并非没有先例。Google的Piper和Meta的Sapling都积累了丰富经验,Anthropic在开发Scion时也参考了这些实践。

Scion主要遵循以下设计原则。

1. 客户端始终在线。

Git假设客户端需要离线工作,因此必须在本地保留完整的代码仓库。但Anthropic的客户端几乎都是Agent和自动化任务,所以围绕始终可访问的服务器来设计Scion的客户端和通信协议。客户端需要什么数据,就从服务器获取什么数据。

2. 客户端和服务器承担不同职责。

在Git中,每个客户端都有能力充当一台完整的Git服务器。Scion则把大部分工作交给服务器,包括查询文件历史和blame信息、创建提交、执行合并与变基等。客户端只负责维护一个大小受限的本地对象缓存、将工作副本中的文件写入磁盘、监控文件系统变化,并提供方便用户操作的接口。客户端自身几乎不需要进行复杂计算,因此本地保存的数据也少得多。

3. 完整的源代码控制服务,可以支持更多新应用。

在Git中,如果CI任务或其他工具想查询代码仓库的信息,比如某一行代码最后是谁修改的,或者两个提交之间有什么关系,通常需要自己维护一份本地仓库。另一种办法是依赖特定服务商提供的API,但这些API未必能回答所有问题。Scion把客户端使用的所有源代码查询功能都开放为API。这样,很多任务根本不需要本地仓库,就能直接完成查询。

Anthropic内部的自动化二分定位和代码回滚流水线就是例子。如果没有这种低成本、可通过程序调用的源代码访问能力,这些工具很难在当前规模下运行。

4. 所有组件都必须支持横向扩展。

过去,Anthropic最多运行过几百台Git镜像服务器,占用了大量计算资源。而且,一旦代码仓库的规模超过单台镜像服务器的磁盘或内存容量,继续扩展就会非常困难。

Scion将代码仓库数据分布式存储,每个组件都可以独立扩展。整个系统中没有任何一份完整实体化的代码仓库,服务器上也没有。Scion也没有与Git packfile(压缩对象包)对应的机制,因此不需要执行相关的仓库维护操作。

5. 提交必须足够轻量、支持增量处理,而且不需要加锁。

在Git中,开发者先在本地提交代码,再通过push将修改共享出去。Scion的所有提交、变基和合并操作都在服务器端完成,因此不需要push。但这样一来,服务器就必须能够快速处理这些操作。创建提交及更新相关数据结构的成本,必须与本次代码变更的大小成正比,而不能随着整个仓库的规模增长。否则,服务器迟早会跟不上代码提交速度。

Scion的开发流程也尽量减少对ref的使用。ref是指向提交的引用,例如分支和标签,通常只保留主分支或发布分支等必要引用。因为需要所有服务器共同维护一致状态的全局数据,未来很可能成为扩展瓶颈。

6. 工作副本可以省略,检出默认只获取需要的数据。

Anthropic的Monorepo非常庞大,CI每天又要执行数千万次代码检出,因此他们希望尽可能避免不必要的检出操作。例如,如果某个CI任务需要计算一次提交与其合并基点之间的差异,可以直接向Scion服务器查询。许多写入任务也可以跳过代码检出,完全通过API完成。

Scion的协议主要围绕稀疏检出和虚拟化检出设计。稀疏检出只包含客户端明确需要的目录,虚拟化检出则在真正需要时才把文件加载出来。这样,即使任务必须在磁盘上使用文件,也只需要获取实际读取的内容。

三、Scion的工作原理

了解了这些设计原则后,我们接着来看Scion是如何实现它们的。这些经验既可以用于其他源代码控制系统,也可能对软件开发流程的其他环节有所帮助。

数据结构

在Scion中,基本工作单元叫做Changeset(变更集),它是预写日志(Write-Ahead Log)中的一条记录。

Changeset保存了Git Commit中的大部分常见信息,但两者的数据组织方式有所不同。Git Commit保存一个指向目录树的指针,而Changeset保存的是相对于第一个父提交发生变化的文件列表,以及指向对象存储中压缩文件内容的内容寻址指针。Changeset在服务器端创建,创建后就能立即从系统各处访问。

Monorepo

Scion中Changeset的数据结构。

这种结构让Scion能够以极高的吞吐量接收变更。因为不需要接收packfile,不需要加锁或跨服务器协调,也不需要移动ref。严格来说,Scion仍然支持ref。但创建和获取提交都不依赖ref,因此移动ref只需要在Spanner的单行数据上执行一次比较并交换(Compare-and-Swap)操作,而且这一操作与创建Changeset是分开的。

不过,Changeset只记录发生变化的内容。单靠这些记录,无法快速回答某行代码最后是谁修改的,或者某个文件经历过哪些提交。为了解决这些问题,Scion会基于Changeset构建额外的数据结构,包括专门用于查询blame和文件路径历史的数据结构,以及用于加速提交图查询的跳表。

Anthropic把不直接属于Changeset的数据统称为Derived Data(派生数据)。所有派生数据都通过一套通用机制计算。每种派生数据都采用递归定义:某个Changeset的派生数据,可以根据其父Changeset的对应数据计算得到。

这套机制有三个好处。

首先,如果发现某项操作可以通过新的数据结构加速,就能方便地增加一种派生数据。

其次,每种派生数据都可以独立决定是提前计算,还是等到真正需要时再计算,从而避免生成用不到的数据。

最后,客户端不需要了解这些数据结构的内部实现,因此可以不断优化服务器端的数据结构,而无须修改客户端。

随着Scion的发展,Anthropic已经多次增加新的派生数据类型,例如用于检测文件复制,以及按路径搜索文件的新索引。

扩展Scion

一组规模不大的Scion服务器集群,负责向客户端提供各种源代码控制API,包括获取Changeset、计算diff、查找合并基点和获取Blob等。所有源代码数据都采用内容寻址方式,因此数据一旦写入,内容就不会再发生变化。任何服务器都可以缓存这些数据,无须与其他服务器确认。

因此,Scion服务器能够横向扩展,彼此之间只需要很少的协调。这些服务器本质上就像大型缓存,同时还能按需计算派生数据,并把结果写回Spanner。

使用Scion的大量内部工具,也不再需要各自维护本地仓库。过去,如果CI任务或其他工具需要查询提交的祖先关系、追踪代码修改记录,就必须先获取并维护代码仓库,这会带来不小的维护负担。实际上,在迁移早期,我们还没有自己的客户端、仓库格式和通信协议,当时Scion只能回答这些元数据查询。相比之下,获取文件内容、在磁盘上生成工作副本,需要传输的数据量大得多,因此我们为这部分能力单独设计了一套方案。

Scion的scn客户端在数据获取协议上与Git有几个重要区别,因此能够采用扩展性更强、CPU开销明显低于Git服务器的架构。Scion在协商数据获取时,不会让客户端先告诉服务器自己已经拥有哪些数据,而是直接请求客户端想要的目录树和Blob对象。客户端从根目录树开始,检查本地存储中缺少哪些目录树对象,再递归向服务器请求。完成目录树获取后,再用同样的方式获取Blob。每次请求都指向一个明确且内容不会变化的对象,因此任何缓存都可以返回结果。

整个架构与传统的分层缓存系统非常相似。这种方式效率很高,而且支持断点续传,因为整个过程不需要依赖单个体积可能达到数GB的packfile响应。稀疏检出和虚拟化检出也不需要特殊支持。客户端只要不请求自己不需要的目录树即可。

在Anthropic的计算集群中,客户端通过Socket与名为scion-daemon的守护进程通信。scion-daemon为整台计算节点保存代码对象。由于大多数节点都需要访问Monorepo,同一节点上的不同任务通常会重复使用大量相同对象,因此由守护进程统一管理缓存更有效率。每个scion-daemon启动时,都会加载一份定期更新的快照。随后,它只与所在Region的目录树和Blob缓存服务器通信,这些服务器被称为scion-cache。

scion-cache直接从内存中传输对象,使用的格式就是守护进程最终要写入磁盘的格式。因此,缓存服务器不需要计算客户端缺少哪些对象,也不需要执行差量压缩。当缓存中缺少某个对象时,scion-cache会向权威服务器scion-server请求。scion-server再根据需要从Spanner或云存储中读取数据。

scion-daemon、scion-cache和scion-server都使用相同的RPC接口,因此客户端不需要了解整个缓存系统的拓扑结构。理论上,任何一层都可以与其他层通信。但Anthropic严格规定了不同层之间的访问关系,以便隔离故障。例如,如果某个Region的scion-cache发生故障,Anthropic不希望大量请求直接涌向上游scion-server,最终导致整个系统瘫痪。

Monorepo

Scion的代码检出架构。

这套系统的每一层缓存命中率都超过99%,而且不需要维护长期状态,因此能够方便地按需扩容。与之前的Git镜像基础设施相比,Scion在CPU和内存方面的资源占用缩小了200倍。CI和研究任务的代码检出速度提高了约两个数量级,从过去的几分钟缩短到几秒钟。这为整个计算集群释放了大量资源,仅CI系统就节省了25%的CPU容量。此外,客户端和缓存服务器都不需要执行仓库维护任务,也让任务的生命周期管理变得更加简单。

四、从开发Scion中学到了什么?

Anthropic开始开发Scion的时间,恰好也是Claude Mythos Preview和Claude Tag开始在Anthropic内部可用的时候。这两个模型一方面进一步增加了我们对Scion的需求,另一方面也明显加快了开发进度。

这里有一个很有代表性的例子。今年早些时候,Anthropic基本靠手工编写了第一版Git到Scion的数据导入流水线原型。当时,Anthropic觉得这套程序已经相当不错了。直到后来拿到了Claude Mythos Preview的一个早期内部版本,Anthropic让Claude重写整个程序,没有给它任何额外指示。结果,Claude直接写出了一版内存消耗降低20倍、运行速度提高4倍的实现,同时完整保留了原程序中关于数据导入顺序和数据结构的所有隐含约束。

Monorepo

2026年1月至9月,Scion和Antique代码库每周合并的代码变更数量。

开发和运行Scion的经历,让Anthropic对面向大规模Agent的软件开发有了一些新的认识。

小团队快速开发大型系统,将会越来越常见

一个只有7人的团队,在5个月内开发了Scion和代码审查工具Antique,还构建了大约半打相关系统,并完成了向这些系统的全面迁移。光是Antique,就足够另外写一整篇工程博客了。

而且,整个开发和迁移过程发生在Anthropic每日代码合并量增长了10倍的时期。放在过去,开发和部署这样一套源代码控制系统,通常需要更多工程师,经过数年的反复迭代和逐步迁移才能完成。

Anthropic认为,未来这种快速、灵活的系统开发和迁移会越来越常见。

工程师依然重要,但工作方式正在改变

参与这个项目的所有工程师,如今都会认为Claude写代码的能力已经超过了自己。但工程师依然发挥着不可替代的作用。团队成员理解各个系统之间的整体关系,也清楚不同架构设计需要作出哪些取舍。Anthropic知道自己要解决什么问题,系统需要支撑多大的规模,因此能够作出合理的设计决策。很多时候发现,工程师的工作就是对Claude说「不」。

Agent有时会为了满足某种代码模式,违反系统原本必须遵守的核心约束。这种情况在迁移过程中尤其常见。例如,有几个系统需要查询某次代码变更是在什么时候合并到主分支的。Claude试图通过线性扫描提交日志来找出答案,而实际上,它完全可以直接向我们的代码审查工具发起查询。

Anthropic也大量采用对抗性代码审查。这种方式在很多方面都非常有效,但有时也会过度关注局部问题。因此,经验丰富的工程师需要及时引导Claude,避免它为了应对假设中的风险,把系统设计得过于复杂。例如,有一次审查对另一个内部服务的可信程度过于谨慎,结果导致Claude加入了大量额外校验,让系统变得更加复杂。目前,Anthropic团队成员仍然会审查这个系统的每一项代码变更请求。不过,现在他们主要检查修改意图是否合理,而不会逐行阅读所有代码。

显著改善了系统性能和代码质量

Claude能够以远快于人类工程师的速度编写大量代码,因此Scion成了Anthropic接触过的测试最充分、防护措施最完善的代码库之一。即使开发时间非常紧张,Anthropic仍然构建了完整隔离、可重复运行的模拟测试,覆盖此前遇到过的各种复杂基础设施交互和源代码控制操作。

此外,Anthropic还加入了模糊测试和完善的限流机制。Claude也经常能轻松发现重要的性能优化机会。例如有一次它发现,某个提交祖先关系查询算法遗漏了一个已有索引,因此存在优化空间。如果交给专家,这样的问题可能需要花上数天甚至数周进行分析和调优。但Claude完成优化之后,第二天又能继续做类似的事情。

Monorepo

Scion原生代码仓库的实际性能提升情况。

为Monorepo的安全管理打下了新基础

对于规模庞大的Monorepo,安全和合规与容量、扩展能力同样重要。Anthropic从设计Scion的一开始就考虑了这些问题。Scion支持丰富的代码仓库访问控制,还可以针对单个目录设置权限。这样,就能保护最敏感的代码,同时保留Monorepo的优势。

此外,Anthropic开发的代码审查工具还支持复杂的、基于语义的审批约束。例如,系统可以区分只修改注释的简单变更,以及涉及敏感程序逻辑的修改。这样,人类审查者就可以把精力集中在影响更大的变更上。

系统运维可以达到新的水平

Anthropic的团队大量使用Claude Tag来监控系统的各个组件,例如专门创建了一些Slack频道,让Claude持续盯着某个组件的运行状况。Anthropic把这些Claude称为Superfans(超级粉丝)。

目前,Anthropic有负责scion-daemon的Superfan、负责scion-cache的Superfan,以及专门关注Antique合并队列的Superfan。它们可以访问系统的遥测数据和日志。这些Claude就像经验丰富、又有大把时间的工程师,会不断刷新监控图表,寻找任何不正常的迹象。

当然,Anthropic仍然为所有系统保留了传统告警。但相比之下,Superfans能够发现一些非常细微、此前从未出现过的问题,让传统告警显得有些单一。

重新思考过去的很多做法

这个项目促使Anthropic重新审视那些为人类开发规模设计的工作流程。例如,在Agent大规模编程的场景下,传统的合并队列可能已经不太合理。当一组测试还在运行时,就可能有几百甚至几千次代码变更被合并进仓库。在这种情况下,CI究竟应该怎样工作?

到目前为止,Anthropic还没能有效复现业界常见的、通过全局仓库锁来管理合并队列的方式。因此,Anthropic把更多精力投入到代码合并后的自动化测试,以及部署前的自动化测试上。当然,这意味着同时进行的代码变更可能发生冲突。但Claude通常能够在人类工程师发现冲突之前,就把问题修复掉。

五、对更广泛的开发者生态意味着什么?

Anthropic认为,Scion只是解决AI Agent能力不断提升所带来的扩展性问题的一部分。分享这些细节,是希望其他团队能够从我们的实践中获得一些启发。

但Anthropic也不认为Scion的方案适用于所有场景。Scion绝不适合作为Git的通用替代品。其介绍的这些设计思路,主要适用于真正庞大的Monorepo,例如由数万名工程师共同使用,或者由大量Agent持续生成代码的仓库。

此外,Anthropic还有一个特殊条件,它能够为内部任务消耗的Token,远远超过其他公司在现实中愿意承担的规模。这样做既是为了满足自身的软件开发需求,也是为了测试Claude的能力。从实际情况来看,要把Scion做成一套能够被其他公司广泛使用的产品,也非常困难。

Scion与Git的差异很大。如果其他公司想迁移到Scion,就需要迁移整个软件开发流程中的各个环节,而且还需要配套的代码审查、代码搜索和CI系统。Anthropic内部的这些系统都经过高度定制,其他公司很难直接采用。

Anthropic也担心,如果试图开发一个满足所有人需求的公开版本,最终做出来的产品反而没有太大用处。不过,Anthropic预计,未来6到12个月内,这类问题会变得越来越普遍。如果每一家使用Git的公司都要独自解决类似问题,显然会浪费大量工程资源。

因此,Anthropic认为,目前最有价值的做法是分享自己的设计思路,让其他开发者能够把Scion中一些行之有效的方案应用到Git上,而无须完全放弃Git现有的整体模式。例如,Git服务器不一定要采用与Git客户端相同的工作方式。目前已经存在一些新的服务器架构,能够明显提高系统的扩展能力。

Git托管平台也可以像Scion一样,提供完整的服务器端RPC接口。这些接口甚至可以在不同代码托管平台之间实现标准化,让Git客户端能够直接调用。Git当前的数据协商协议也不一定需要维持原样。此外,Git现有的稀疏检出、浅克隆等功能,也可以进一步改进,让它们更好地配合使用。