Hacker News 中文摘要

RSS订阅

Anthropic 重构内部源代码管理系统 -- Redesigning source control at Anthropic

在 Anthropic(Anthropic),编码已不再是瓶颈:克劳德(Claude)能自主迭代研究、微优化程序并从零构建服务。真正的瓶颈是为人类尺度设计的开发者基础设施,包括源代码管理、构建和 CI。2026 年 5 月,Anthropic 日均合并约 2500 项代码更改;到 2026 年 9 月,日均合并已超过 30000 项。为此,团队用五个月把单体仓库从 Git(Git)完全迁移到自研版本控制系统赛昂(Scion)。

正文

在 Anthropic,编码不再是构建系统或进行研究的瓶颈。Claude 能够自主迭代研究循环、对复杂程序进行微优化,并以前所未有的速度和规模从零构建新服务。如今的瓶颈,是那些为人工规模构建的开发者基础设施:源代码管理、构建和 CI。

2026 年 5 月,Anthropic 平均每天合并约 2,500 次代码变更;到 9 月,我们每天合并超过 30,000 次。我们不认为这种增速会很快放缓;合并代码的潜在需求实际上是无限的,而我们每消除一个瓶颈,就会立刻导致产出的代码量进一步增加。

2026年1月至9月,我们的单体仓库(monorepo)每天合并的代码变更数

为了支撑这种增长,我们构建了 Scion——一套内部自研的版本控制系统,并在五个月内将我们的单体仓库(monorepo)从 git 完全迁移了过去。同一时期,我们还构建并上线了一个代码审查界面(名为 Antique)、代码搜索、一套丰富的源代码管理 IAM 系统,以及管理和落地大量已审查代码的新方式等等。我们在此重点讨论 Scion 自身的构建过程。这是一个很有意思的案例:Claude 写代码的能力既是一开始让我们陷入这种处境的原因,也是我们能够快速构建出高质量、可扩展系统来应对它的手段。

扩展我们的单体仓库

在探讨我们构建了什么之前,应该先承认我们的工作负载有多不寻常。不出所料,Anthropic 使用 Claude 编写软件的程度远超几乎所有其他公司,因此我们常常最先看到那些为人工规模打造的工具开始吃力。源代码管理只是其中一个例子。虽然我们不认为很多组织会在短期内遇到这些问题,但我们怀疑,其他使用 AI 编码工具的人体验到同样压力点的时刻不会太远,这也是我们想分享自己构建了什么、学到了什么的原因。

Git 是一个去中心化系统:每个克隆都是一个完整、自包含的仓库,可以在完全离线的情况下计算差异、读取历史和归属(blame),并检出任何版本。对绝大多数仓库来说,这是正确的设计,也是 git 成为标准的重要原因。

随着我们的单体仓库不断膨胀,它越来越不符合这种设计空间。仅主分支的历史就接近 100 GB,而一个压缩后的工作副本超过 25 GB。我们每天为 CI 执行大约 2,500 万次代码检出,这还不算开发者环境、智能体沙箱和研究任务。如果按原始方式拉取,每天将产生超过 600 PB 的 git 流量。

Git 提供了一些处理仓库切片的手段,比如浅克隆、稀疏检出和 promisor remote。除此之外,针对大型单体仓库还有一些标准变通方案,比如内部 git 镜像,以及保存在 blob 存储中的仓库快照(称为 seed)。这些我们都用过——在峰值时,我们运营了数百个内部 git 镜像来应对负载。这为我们争取了时间,但随着合并速率上升,它们的运维变得越来越困难。seed 在两次刷新之间会越来越落后于主分支的尖端,而且要让依赖历史的操作(如 diff 和 blame)在部分克隆上正常工作,需要投入越来越多的精力。

扩展 git 检出规模的典型设置

退一步看,我们发现:和大多数公司一样,我们把 git 当作拥有一个权威副本的中心化系统来用,但我们的客户端几乎全都是在定义上就始终在线的智能体和任务。那些让 git 非常适合分布式、离线工作的特性,反而随着仓库变大在不断损害我们的扩展能力。于是我们问自己:如果从一开始就假定智能体永远在线来设计源代码管理,它会是什么样子?

面向智能体规模的源代码管理原则

在智能体编码的时代,关于软件如何开发的许多常见假设都在演变。我们在构建 Scion 时拥抱了这些变化,这让我们得以在几个核心原则上采取与 git 根本不同的做法。面向超大型单体仓库的源代码管理已有先例, notably Google 的 Piper 和 Meta 的 Sapling,因此我们在构建 Scion 时能够借鉴它们来之不易的经验。我们的原则如下:

  • 客户端永远在线。 Git 假定客户端离线工作,并需要一份完整的仓库副本。由于我们的客户端几乎都是智能体和任务,Scion 的客户端与协议围绕一个始终可访问的服务器来设计,客户端只在需要时拉取数据。
  • 客户端与服务器不对称。 在 git 中,每个客户端都能充当完整的服务器。在 Scion 中,服务器负责回答文件历史和归属问题、创建提交、执行合并和变基等等。客户端维护一个有上限的本地对象缓存,把工作副本文件布局到磁盘上,监控文件系统变化,并为用户提供与服务器协作的顺手方式。它自身能做的计算很少,但换来的是本地所需数据大幅减少。
  • 全面的源代码管理服务能支撑许多新应用。 使用 git 时,如果一个 CI 任务或工具需要询问仓库问题,比如谁最后改了某一行,或者两个提交之间是什么关系,就必须维护一份本地仓库副本,或者指望供应商特定的 API 给出答案。而在 Scion 中,客户端使用的所有源代码管理查询也都通过 API 暴露出来,因此在很多情况下任务根本不需要本地仓库。我们的自动二分(bisect)和回滚流水线等许多内部工具,如果没有这种对源代码管理的廉价、可编程访问,在大规模下根本不实用。
  • 一切都必须可水平扩展。 在峰值时,我们运行了数百个 git 镜像,这给容量带来了巨大压力,而且一旦仓库增长超出镜像的磁盘或内存限制,就再也无法扩展。在 Scion 中,仓库数据是分布式的,每个组件都能独立扩展;任何地方,甚至服务器上,都没有完全物化的仓库副本。它也没有 packfile(git 压缩后的对象包)这类东西,因此不需要仓库维护。
  • 提交必须廉价、增量且无锁。 在 git 中,你在本地提交,然后推送来分享工作。在 Scion 中,每一次提交、变基或合并都发生在服务器端,所以没有要推送的东西,但这些操作都必须很快。创建提交并更新其下游数据结构的成本,必须随变更的大小而扩展,而不是随整个仓库的大小扩展,否则服务器跟不上。Scion 的开发生命周期不鼓励使用 ref(指向提交的指针,如分支和标签),只有主 ref 或发布分支例外,因为每个服务器都必须达成一致的全局状态是一个迫在眉睫的扩展问题。
  • 工作副本是可选的,而且天生稀疏。 由于我们的单体仓库非常大,而且每天为 CI 检出代码达数千万次,我们希望尽可能避免检出。在 Scion 中,例如,一个需要某提交与其合并基(merge base)之间差异的 CI 任务,可以直接向服务器请求。写入也一样:很多写入负载也可以跳过检出,完全通过 API 完成。Scion 的协议围绕稀疏检出(只包含客户端请求的目录)和虚拟化检出(按需物化文件)来设计,因此当任务确实需要磁盘上的文件时,客户端只为自己实际读取的内容付费。

Scion 如何工作

理解这些原则在构建 Scion 时如何落地会很有帮助。这些洞察也适用于其他源代码管理系统,或者更广泛地说,适用于软件开发生命周期的其他阶段。

数据结构

在 Scion 中,工作单元是一个“变更集(changeset)”,也就是预写日志(write-ahead log)中的一条记录。变更集存储了你在 git 提交中所期望的大部分内容。但 git 提交存储的是指向树的指针,而变更集存储的是相对于其第一个父提交发生变化的文件列表(对合并而言,相对于第一个父提交来存储变更文件是一种风格选择;实际上,在单体仓库的主干开发模式下,人们只关心主线提交的历史或归属),以及指向 blob 存储中压缩文件内容的内容寻址(content-addressed)指针。变更集在服务器端创建,并即刻在任何地方可用。

Scion 中变更集(changeset)的结构

这种结构让我们能以极高的吞吐量接收变更集,因为不需要接收 packfile,不需要加锁或跨服务器协调,也不需要移动 ref。Scion 技术上确实支持 ref,但由于创建和获取提交都不涉及 ref,移动一个 ref 只是对单个 Spanner 行做一次比较并交换(compare-and-swap),且是独立于创建变更集发生的。

变更集只记录了变动内容,因此它本身无法快速回答“谁最后编辑了某一行”或“哪些提交影响了某个文件”这类问题。为了回答这些,Scion 会从变更集中构建额外的数据结构,包括专用的文件归属(blame)和路径历史结构,以及提交图的跳表(skip lists)。我们把所有不直接属于变更集的东西称为“派生数据”,并通过一种通用机制来计算它们。每种派生数据都是递归定义的,因此一个变更集的某种派生数据的值,是根据其父变更集的对应值计算出来的。

这一机制有三个好处。第一,当某种新数据结构能让某个操作更快时,我们可以轻松添加新类型的派生数据。第二,对每种类型,我们可以选择立即计算还是推迟工作,从而避免物化不需要的数据。第三,由于客户端永远看不到这些数据结构的内部实现,我们可以在不改动客户端的情况下优化它们。随着系统成长,我们多次添加了新的派生数据类型,例如用于执行复制检测或基于路径的文件搜索的新索引。

扩展 Scion

一小组 Scion 服务器为客户端需要的任何操作提供源代码管理 API,例如获取变更集、计算差异、寻找合并基,以及拉取 blob。所有源代码管理数据都是内容寻址的,因此一份数据一旦存储就永不改变,任何服务器都可以缓存它而无需与其他服务器核对。因此,这些服务器是可水平扩展的,且几乎不需要协调。它们本质上就是大型缓存,同时还能即时计算派生数据并把结果写回 Spanner。

Scion 的众多消费者不再需要维护自己的本地仓库。过去,对于那些需要询问源代码管理问题(尤其是关于提交祖先和归属)的 CI 任务或工具来说,拉取和维护仓库曾是一项重大的运维负担。在迁移早期,在我们还没有自己的客户端、仓库格式或协议时,Scion 只回答这些“元数据”查询。拉取文件内容和物化工作副本是数据密集得多的操作,它们需要属于自己的设计。

Scion 的 scn 客户端在几个重要方面偏离了 git 的获取协议,因此它天然适合一种高度可扩展、且比 git 服务器所需 CPU 少得多的架构。Scion 的协商不会告诉服务器客户端已经拥有什么;相反,它只针对客户端想要的树和 blob 进行操作。从一个根树开始,客户端检查本地存储中缺失的树并递归请求它们,然后对 blob 重复该过程。每个请求都是针对一个永不改变的特定对象,因此任何缓存都能回答,该架构也非常接近传统的分层缓存。这个过程还是高效且可恢复的,因为不存在单个数 GB 的 packfile 响应。稀疏甚至虚拟化检出都不需要特殊支持,因为客户端 simply 不会去请求它不想要的树。

在这套机群中,客户端通过套接字与一个守护进程通信,该守护进程称为 scion-daemon,为整个节点存储对象。我们的大多数节点都需要访问单体仓库,而同一节点上的任务会复用大部分相同的对象。每个守护进程从一个定期刷新的快照开始,然后只与所在区域的树和 blob 缓存服务器通信,这些缓存服务器称为 scion-cache。这些缓存服务器直接以守护进程将消费的磁盘格式从内存中流式传出对象,因此它们不需要花时间计算客户端缺失的对象或执行增量压缩。当某个缓存缺少一个对象时,它会去问权威的 scion-servers,后者根据需要从 Spanner 或云存储中读取。

scion-daemon、scion-cache 和 scion-server 对该协议响应完全相同的 RPC,因此客户端不需要知道缓存拓扑。任何一层理论上都可以与另一层通信,但我们严格执行分层以隔离故障域。我们希望避免出现这样一种情况:某个区域 scion-cache 的故障压垮上游的 scion-servers,进而拖垮整个系统。

Scion 的检出架构

该系统的每一层都保持着超过 99% 的缓存命中率,且不需要长期状态,因此在需要时很容易扩容。就 CPU 和内存需求而言,我们的 Scion 基础设施占用现在比之前的 git 镜像基础设施小了 200 倍。CI 和研究任务检出代码的速度快了两个数量级(从几分钟变成几秒钟),这在整个机群中释放了相当可观的容量;仅 CI 就实现了 25% 的 CPU 容量收益。客户端和缓存都不需要执行仓库维护,这简化了我们任务的生命周期管理。

构建 Scion 的过程中我们学到了什么

我们开始构建 Scion 的时间,差不多正是 Claude Mythos Preview 和 Claude Tag 在内部可用的时间。这两个版本的发布同时放大了对 Scion 的需求,也显著加快了我们构建它的速度。

这里有一个特别惊人的例子。年初,我们基本是手写完成了 git 到 Scion 的摄取流水线的第一个版本作为原型。我们觉得它不错——直到我们拿到了 Claude Mythos Preview 的早期内部快照。我们让它重写整个东西,在没有任何进一步指示的情况下,它产出的一个版本内存消耗减少了 20 倍,速度提高了 4 倍,同时保留了关于摄取顺序和数据结构的所有隐含不变式。

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

构建和运营 Scion 让我们学到的东西,为“构建智能体规模的软件可能是什么样”提供了一些有趣的教训。

  • 小团队的快速开发将变得更加普遍。 一个七人团队构建了 Scion 和 Antique(我们的代码审查工具,关于它我们完全可以再写一篇博客),更不用说六个相关系统,并在五个月内完成了全面迁移。我们在做这些的同时,每日合并的代码量增长了 10 倍。过去,开发和部署这样一套源代码管理系统,需要一家公司花上数年、多次迭代迁移,并投入多得多的工程师。我们认为这种快速、灵巧的迁移在未来会变得更常见。
  • 工程师的价值丝毫未减,但他们的工作内容在变化。 参与该系统的所有工程师现在都会认为,Claude 在写代码方面比他们更强。但我们的工程师仍然提供了对高层跨系统组件和设计层面取舍的宝贵理解,围绕我们想要解决的问题和必须达到的规模做出明智选择。我们经常发现,工程师的角色是对 Claude 说“不”。智能体有时会为了满足某种本不该被允许的模式,而违反核心系统约束。这在我们的迁移过程中尤其常见。例如,有多个系统试图通过线性读取提交日志来暴力查找某个变更何时合并到主线,而不是去问我们的代码审查工具。Anthropic 也大量使用对抗性审查,虽然这在很多方面极其有效,但也可能目光短浅,因此需要熟练的工程师引导 Claude,不要为了应对假想的问题而过度设计系统的某些部分。例如,有一场审查对另一个内部服务的信任过于防御,导致 Claude 增加了过多的验证和复杂性。我们的团队成员仍然审查该系统的每一个变更请求,但他们现在检查的是变更的意图,而不是逐行阅读代码。
  • 我们得以大幅优化并提升质量。 得益于 Claude 能以远超我们自己的速度编写海量代码,Scion 是我们迄今见过测试最充分、防御最严密的代码库之一。即使在紧张的工期下,我们也为遇到的每一种重要的基础设施和源代码管理交互构建了封闭模拟(hermetic simulations),以及模糊测试和精密的速率限制。Claude 还随手发现了重要的优化——例如,一个祖先查询的算法优化,它漏掉了我们的某个索引——而这本来需要一位专家花几天或几周分析调优……然后它第二天又做了一遍。

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

  • 我们为新型单体仓库安全打下了基础。 在庞大的单体仓库中管理安全、安保与合规,与管理其体量和规模同等重要。我们从一开始构建 Scion 时就考虑到了这些。它支持对仓库丰富的访问控制,并且能够对单个目录施加权限,从而在保护最敏感代码的同时,不失去单体仓库的好处。此外,我们构建的代码审查工具可以表达复杂的审批语义约束,这让我们能把像“仅注释变更”这样简单的事情和敏感的逻辑变更区分开,从而让人类审查者专注于最重要的变更。
  • 一种全新的运维卓越水平成为可能。 我们的团队大量使用 Claude Tag,这帮助我们监控系统的每个组件。例如,我们创建了 Slack 频道,在其中让 Claude 痴迷地专注于单一组件的健康状况。我们称这些 Claude 为“超级粉丝(superfans)”。我们有 scion-daemon 超级粉丝、scion-cache 超级粉丝、Antique 合并队列超级粉丝等等。它们能访问我们的遥测和日志,表现得像一位经验丰富、除了刷新图表和寻找任何异常之外无事可做的工程师。我们也为所有系统设置了传统告警,但相比之下,我们的超级粉丝能发现那些让传统告警显得单维的微妙而新颖的问题。
  • 我们正在彻底反思自己的先验假设。 这个项目促使我们极其认真地审视其他为人工规模设计的工作流。例如,在智能体规模下,一个正经的合并队列并没有多大意义。当成百上千个变更可以在测试运行期间合并时,CI 到底意味着什么?我们一直无法有效复现合并队列上全局仓库锁这一行业标准,因此转而投资于合并后和部署前的自动化测试。这确实意味着并发变更可能发生冲突,但 Claude 通常能在人类甚至识别出冲突之前就修好它们。

为更广泛的生态做贡献

在我们看来,Scion 只是应对日益强大的 AI 智能体所提出的规模问题的答案之一。我们分享这些细节,是把它当作团队如何应对类似挑战的一个例子,尽管我们并不指望我们的方案或考量适用于所有情况。

Scion 绝不适合作为通用场景下 git 的替代品。我们在这里概述的概念,真正只对那种动辄拥有数万名工程师、或是有成群智能体在大量编写代码的超大型单体仓库才有意义。此外,Anthropic 是独特的:我们在内部使用上花费 token 的能力,远远超过任何其他企业实际愿意承担的水平。我们这样做既是为了满足自身的软件开发需求,也是为了测试 Claude 的能力。

从实际出发,很难把 Scion 做成一种对其他组织 broadly 有用的形式。它与 git 差异巨大,意味着企业必须迁移开发生命周期的每一环,而且它需要配套自有的代码审查、代码搜索和 CI。我们这些组件的内部版本高度定制化,因此其他组织很难采用;而且我们担心,试图构建一个取悦所有人的公开版本实际上并不会有多大用处。

然而,我们预计这类问题在未来六到十二个月会变得更加普遍,而让每一家使用 git 的公司都独自面对类似挑战,将是工程资源的低效利用。有鉴于此,我们认为我们能做的最有影响的事,就是分享我们的思考,让其他开发者能够把 Scion 中一些最成功的地方应用到 git 上,而不必脱离整体模型。git 服务器不一定要和 git 客户端以同样的方式工作;现在已经存在能提供显著扩展性改进的新颖服务器架构。git 平台可以提供像 Scion 那样全面的服务器端 RPC,也许甚至能以跨平台 forge 的标准化方式提供,让 git 客户端学会与之对话。协商协议也不必非得长成今天这个样子,git 中各种稀疏和浅层特性也可以被很好地组合起来。

最后,我们想承认,git 社区已经花了近二十年时间为数百万开发者扩展这个平台。我们的贡献要狭窄得多:分享我们对智能体软件开发如何与这些系统交互的早期观察,以便我们能和 GitHub、GitLab 以及开源社区合作,支持开发者不断变化的需求。在软件开发生命周期与 AI 指数级发展交汇之际,我们所有人都身在其中。

评论

讨论气氛是惊讶中带着怀疑:不少人承认超大规模单体仓库加智能体已经撞到 Git 的扩展上限,因而同情 Anthropic 自研 Scion;但更多评论质疑这种把提交、变基和合并都搬到服务器端的集中式设计,认为它丢掉了 Git 本地历史的好处,并像大厂又一次重复造轮子。分歧主轴于是变成:这究竟是面向智能体时代的必要进化,还是只服务 Anthropic 自家规模、外人难以受益的闭门方案。

认为超大规模单体仓库和智能体确实已经超出 Git 的能力

  • Anthropic 的主分支历史接近 100 GB、压缩后的工作副本仍超 25 GB,若按朴素方式取回,流量会达到 PB 级;当大量智能体并发提交时,Git 的扩展瓶颈会先于人类协作习惯到来。文章也坦承借鉴了 Google Piper、Meta Sapling 等先前经验,甚至有评论认为若说哪家工程组织真需要自研版本控制,那就是 Anthropic。(较多人) > 看到大实验室公开谈这个问题,正好验证了我们的判断:大团队加智能体在单体仓库里迟早会撞上 Git 的扩展极限。(@steveklabnik)

认为拥有内部前沿模型会带来压倒性优势,最终行业只剩前沿实验室

  • 用内部模型重写从 Git 到 Scion 的导入管道,能在没有额外指令的情况下把内存占用降到二十分之一、速度提到四倍,并保住隐含的不变量;据此,手里只有次一等模型的公司会在通用开发上被远远甩开。顺着这个逻辑,也有人担心前沿实验室最终能把所有软件都做得比现有产品更好,其他公司只能沦为供应商。(较多人) > 家里有这种模型的好处怎么说都不夸张,拿着次一等模型来竞争的公司,在通用开发上会被远远甩开。(@trnvll)

质疑服务器端集中式设计是在丢掉 Git 的核心优点,甚至像 SVN 翻版

  • Scion 把提交、变基、合并都放到服务器完成,被读者认为退回老式集中式模型,有人直接类比成 SVN/Subversion;更实质的批评是,Git 和 jujitsu 的好处本可以在本地自由积累、重做、丢弃历史,而新设计强迫智能体先把改动上传再让人判断,还带来智能体越界协作的安全风险。可以造更好的系统,但不能把 Git 真正的优点一起丢掉。(较多人) > 但别因为要造比 Git 更好的系统,就把 Git 真正的优点也弄丢了。(@amluto)

认为这又是一家大厂重复造轮子、加剧版本控制碎片化

  • Google 有 Piper,Meta 有 Sapling,现在 Anthropic 又搞 Scion;内部代码评审、搜索、持续集成都高度定制,外部很难直接采用,甚至有人直接嘲讽没哪个清醒的人会把源码交给这种自研系统。评论对这种“每个大厂都有自己的版本控制”感到疲惫,担心行业不收敛,也有人怀疑它抬高迁移成本、让用竞争对手方案更困难。(较多人) > 我们就不能收敛到一个统一的解决方案吗?(@vitacoco)

质疑规模叙事:数字未必证明必须自研新系统

  • 每天三万提交、600 PB 流量看起来吓人,但按员工数摊下来并不异常;更可能的问题是存在大量横切整个代码库的巨型改动,以及 Git 克隆太慢。也有人直接问:真有那么多代码需要每天改吗?(较多人) > 这数据量和流量听起来太夸张了,真有那么多代码需要每天改吗?(@bix6)

担心三万提交/天之下的评审质量和人类监督名存实亡

  • 即使工程师只看改动意图而不逐行读码,一天三万个拉取请求也极难审;评论担心模型会为了走通流程而抄近路、绕过核心约束,或者干脆没有人工评审就上线,让客户在生产环境里帮 AI 找 bug。也有人纳闷,既然官网和命令行看起来没变,这些提交到底改了什么。(较多人) > 照这个说法,是不是等于没有人工评审就发版,以后客户在生产环境里帮 AI 找 bug?(@jareds)

认为工程师的价值转向高层设计和对智能体踩刹车

  • 文章里工程师仍审查每个改动的意图,只是不再逐行读码;他们负责理解系统间取舍,在智能体为了局部模式违反核心约束、或对抗式评审诱导过度防御时明确说“不”。(少数人) > 团队仍然审查每个改动的意图,工程师的角色经常就是告诉 Claude“不行”。(@tetraodonpuffer)

有价值的补充

  • 把提示词当作源代码提交,AI 生成的代码则像昂贵的构建产物留在仓库里;这和大型游戏、3D 资产的版本控制很像,因为生成物体积大、重建成本高。(@amelius、@willmeyers)
  • 有结合自身经验的补充:Git 在上百个提交并行落地时性能会严重退化,所以有人把改动压成每日批次,牺牲粒度换稳定;若代码生成速度再涨两个数量级,就只能放弃 Git。(@rfgplk)