2026年10月13日,Anthropic发布了一篇文章,介绍他们内部的新一代源码控制系统Scion。促使他们改造源码控制系统的动力是,他们的规模在4个月内突然暴涨。2026 年 5 月,Anthropic 的大仓库每天平均有 2,500 个变更合并到主分支,到 2026 年 9 月涨到了每天超过 30,000 次。短短四个月,每天合入的变更次数涨了十倍不止。越来越多的 agent 和自动化任务在提交代码,那些按人类规模设计的研发基建也就顶不住了,源码控制、构建和 CI 系统率先出现瓶颈。
从存储和带宽的角度看,git 系统已经撑不住了。Anthropic 主分支的历史大小接近 100GB,即便压缩后每个工作副本也有 25GB+。再加上 CI 和自动化任务每天要拉取约 2,500 万次代码,如果每次都完整 clone,内网每天搬运的代码就超过 600PB。为了支撑 git,Anthropic 曾部署几百个内部 git mirror 节点,并用对象存储的仓库快照做 seed 再同步增量。即便如此,系统仍然经常挂掉。
那为什么经过时间考验的 git 在这里失灵了呢?这是因为 git 从诞生起,它的核心用户就是人。git 2005 年诞生时,一个核心目标就是让开发者即使离线也能照常工作:背着笔记本在断网的十几个小时里,照样可以提交、切分支、翻几年前的历史、比较任意两个版本之间的差异。为了支撑这种偶尔离线的场景,git 选择了客户端和服务端对等的架构:每次 clone 一个仓库到本地的时候,默认要把整个仓库的提交历史和文件对象图从头到尾都下载下来,所有的历史追溯、差异计算、分支合并都在本地完成。只要屏幕前坐着的是每天只拉几次代码、守着同一个工作目录写上一整天的人,这种离线对等的设计就非常优雅。
但到了今天的 Anthropic 内部,源码控制系统的头号用户已经换了。每天发起两千多万次检出、提交三万多次变更的主力,不再是坐在飞机上敲键盘的程序员,而是机房里永远在线的 agent 和自动化 CI 任务。这批机器客户端有两个跟人正好相反的特征:第一,它们永远连着高速数据中心网络,根本没有离线办公的需求;第二,它们的生命周期极短,经常为了修一个 bug、跑一次测试就临时拉起一个沙盒,干完活便销毁,不少任务甚至只需要看一眼两次提交之间的差异,连本地工作目录都不用建。
用给长生命周期、经常离线的人类设计的对等系统来伺候短生命周期、永远在线的机器集群,原来的设计优势全都成了包袱。为此,Anthropic 抽调了 7 名工程师,花了 5 个月时间从头写出了 Scion,把整个单体大仓从 git 全量迁了过去,同时把代码评审工具 Antique、代码搜索、源码级权限管控,以及自动二分定位与回滚管线等半打配套系统全都重做了一遍。
看到 7 个人在 5 个月里换掉整套版本控制底座,很多人的第一反应都是为什么要造这么重的轮子,在老系统上继续加缓存、打补丁难道顶不住吗?这笔账我们不久前在姊妹篇《CI 的第二层红利:重写变便宜之后,补丁不再回本》里,已经用 Anthropic 自己的 CI 测试筛选服务算过一次:agent 一让仓库流量涨起来,旧架构上打补丁能买到的平稳窗口就迅速变短;另一边,AI 辅助编程又把重写一套系统的工期和人力门槛压得很低。一头是补丁的保质期越来越短,另一头是重写的固定成本越来越低,以前那种先凑合打补丁、实在撑不住再重写的盈亏平衡点已经明显往前挪了。Scion 只是把同一本经济账从外围的 CI 服务一路往下算,算到了最底层的版本控制系统头上。
既然头号用户是永远内网的机器,客户端自然不必像人类笔记本那样把整座仓库背在身上。Scion 干脆拆掉了客户端与服务端对等的设计,让两边完全分工:服务端握全量历史、做所有费 CPU 的重计算;客户端只留一块有界的本地对象缓存,自己几乎不做计算,很多时候连本地仓库都不检出,直接调服务端 API 完成工作。顺着读代码、写与查、主干合入以及人的分工这四个关键场景去看,就可以看见这套”轻客户端、重服务端”的思路怎么落地。
具体来看,对于最频繁的拉取代码操作,我们平时用电脑进行git操作的时候,git客户端需要和服务端进行协商,汇报自己的本地有什么提交,然后服务端再根据提交图现场比较计算,得出客户端需要哪些文件和目录对象,临时压缩打包成一个专属的大文件发送过来,这个现场打包的文件叫packfile。人一天拉几次码没啥,但一天 2,500 万次从零启动的检出,每次都要跟服务端对账、由服务端现场挑对象打包成 packfile,这套流程很快就把几百台内部 git 镜像节点的 CPU 和内存吃满了。更麻烦的是,每次打包的结果因为客户端当时的本地状态不同,也会不一样,所以中间层没法做像缓存静态文件那样的通用缓存。
要想成千上万的机器共享缓存、不用每次都重新打包,前提是每个文件都要有固定的地址。Scion
直接用文件内容的哈希值当存储地址:相同的内容会算出来一样的地址,改一个字就会变成新地址,因此相同的内容会自动只存一份,自动去重。而且同一个地址指向的内容不会变,所以任何中间缓存节点只要存过这个地址,就可以直接告诉客户端不用再问服务器是否有过期。这种用内容算出的哈希当地址的机制叫内容寻址。靠内容寻址,Scion
直接废了 packfile,它的客户端工具 scn
和服务端协商时不汇报自己有什么,而是从根目录树开始往下走,缺哪个目录/文件的哈希块就直接递归去要,传了一半断了也可以随时恢复。
有了内容寻址做基础,所有文件和目录都成了永不过期的静态块,那几百台各自维护整座仓库、现场算包的
git
镜像节点就可以全撤掉,换成三层缓存。为什么要分三层,是因为机房里每时每刻都有大群任务在读同一批代码,离任务越近的地方越快但装得越少,离全量数据越近的地方装得越全但路也越远。Scion
的思路是先在宿主机本机找,找不到再去机房共享内存找,实在没有才去云端存储拿,一层比一层更靠近全量真数据。第一层是跑在每台宿主机上的本机守护进程
scion-daemon。同一台机器上先后拉起的短期 agent
容器直接共用这份本机缓存,前一个任务刚拉过的文件,后一个任务在本机就能直接读。要是本机没有,请求就往上问第二层的区域缓存
scion-cache。它把大家常读的热数据直接按磁盘格式常驻内存,命中后流式下发,省掉了解包开销。只有前两层都没命中的冷数据,才会走到第三层的权威服务端
scion-server,回源去云端存储里读取。这三层对外是接口一致的同构
RPC 服务,彼此故障域严格隔开,整条读取链路就像 CDN 一样逐层回源。
一旦缓存通路理顺,客户端也就自然不用再做全量克隆,而是支持两种按需拉取模式:一种是在事先知道只涉及哪些模块的情况下,直接把当前任务需要用到的子目录拉取到本地硬盘,其他目录一概不碰,也就是稀疏检出;另一种是先只在本地挂一个空目录骨架,看上去文件都在,实际还没下载,等进程真的去读某个文件时,在后台按需拉取,也就是虚拟化检出。对于只看一眼代码差异的 CI 任务,连目录都不用建,直接调用服务端 API 拿 diff 就行。Anthropic 实测报告说,这套三层缓存每一层的命中率都超过 99%,整套源码控制基建占用的 CPU 和内存相比原来的 git 镜像集群缩小了 200 倍。单次检出从分钟级降到秒级,还顺手给整个 CI 省了 25% 的 CPU,客户端和缓存层也都免去了定期维护仓库的活。
写代码查历史也一样,日常改动代码除了直接提交,还要把两条改动线接到一起(合并),或者把自己的改动挪到最新主干后面重接一遍(变基)。git 每次提交都要存一个指向整棵目录树的快照指针,仓库一大,提交、合并或变基的开销都会跟着受拖累,服务端接收 packfile 和挪动大量分支指针又得加锁协调。到了查询环节矛盾更突出:研发工具经常要逐行追溯某行代码是谁写的(blame 查询),或者在合并前顺着历史往上找两个分支的最近共同祖先(merge base)。要是让一个个临时拉起的 agent 容器在本地遍历 100 GB 历史去算 blame 和 merge base,根本跑不动。
Scion 的做法是写入和重查询都放到服务端去做,每次提交的基本单位是一个 changeset。一个 changeset 不会去存储整个目录树的指针,而只会记录这次相对于第一个父提交具体改动了哪些文件,以及指向这些文件内容的内容寻址指针。服务端在保存 changeset 的时候,也不会原地去改复杂的树形结构,而是像记流水账一样,每次只在日志的末尾顺序追加一条新记录,这种只追加不改写的预写式日志机制一般叫做 WAL。不论是提交、合并还是变基,都在服务端直接生成 changeset 追加到末尾,写入后即处可见。因为不用改整棵树、也不用原地改旧数据,每次写入的开销只和这次改动了多少个文件成正比,整个仓库有多大和它没有关系了。
为了解决写入时的争用问题,Scion 还大幅度削减了分支指针的数量。在 Git 中,分支指针是一个名字,它指向当前最新的提交,比如主干叫 main,或者开发时随手建立的特性分支名,这些名字指针统称为 ref。如果有几千个工程师和成群的 agent 在仓库里建立分支的话,就会有成千上万个这样的名字。问题的关键在于,这些名字是全局共享状态:服务端得协调好每个名字此刻指向哪里,一旦有成千上万个改动并发地挪动它们,协调本身就成了瓶颈。Scion 平时尽量避免使用 ref,仓库中几乎只有 main 和发布分支,开发过程中的提交不需要注册成全局分支名。因此在创建 changeset 的时候,既不收 packfile,也不需要跨节点加锁或者移动 ref。只有在合入主干、必须更新 main 这个全局名字的这一刻,服务端才会去 Google 的全球分布式强一致数据库 Spanner 中对单行记录进行一次原子操作:先看一眼旧提交号是否改变,没改变才写新提交号,也就是常见的 CAS 操作。
而用于查历史的 blame、路径历史、提交图的跳表等查询数据则没有新增任何事实——只要有基本的changeset流水账,就可以随时像从银行流水算余额一样把它们推算出来,不需要人手动提交维护。Scion把这类可以从基础提交记录中随时递归推算出来的二级索引统称为derived data。服务端用同一个通用的机制来计算derived data,可以提前算好,也可以按需推算。因为客户端只能调API,看不见内部结构,所以在工程团队在后台升级索引的时候,客户端完全无感。目前已经陆续加入了复制检测和按路径搜索的索引。开发期间,Claude 还发现祖先查询漏用了一个已有索引,顺手做了一处算法优化。
写完能读能写以后,第三块撞墙的地方是主干合入关卡。大型工程团队一般会在主干前放一道自动化门禁,让所有待合入的改动排成一队,挨个基于最新主干跑完完整测试、确认全绿才放进主干,这个排队机制叫merge queue。
每天只有几百次人类提交的时候,merge queue 运转良好;但当合入量冲到每天 30,000 次、主力变成全天候运行的 agent 时,正经的 merge queue 就不通了。每次合入都要先排队跑测试,队头的改动跑测试要好几分钟,后面成千上万个改动只能干等;而且单体大仓只有一个 main,这支队伍没法拆到多台机器上并行合入——高并发下等于给整个仓库加了一把慢速的全局排他锁。为此,Anthropic 转向合入后、部署前的自动化测试,先把代码合进主干,再配合自动二分定位与自动回滚管线把有问题的提交摘出去。高并发直接合入确实会让代码冲突变多,但团队试下来发现,让 Claude 自动修冲突的速度比人类工程师识别出冲突还要快。
第四个瓶颈落在人身上。这 7 个人一边要把 Scion 和半打配套系统写出来,一边还得守住代码质量,对系统本身的每一个改动都做人工审查;而与此同时,全公司的合并量已经涨了 10 倍,靠逐行读完 AI 写的代码根本不现实。可要是完全放手让 agent 自写自审,又会踩中两个反模式:一个是 agent 会照抄老代码里本不该存在的坏模式而违反架构约束,比如内部以前有好几个系统为了查提交合入时间,不去调评审工具接口,而是直接从头到尾线性扫描整条提交日志,agent 写代码时就会顺着这种坏习惯继续写;另一个是对抗式代码审查视野短浅,负责挑刺的 agent 会没完没了地抛出假想风险,逼着 Claude 过度工程化、一层层叠加过量的防御校验。
在摸清这两个脾气之后,团队决定只对每个改动的意图和系统边界做审查,而不是逐行阅读具体实现。工程师的主要责任是提供高层的系统理解,做出设计决策,很多时候就是跟
Claude
说不。底层正确的实现由不依赖外部环境、可以精确模拟并发顺序的密闭确定性仿真,以及随机输入异常输入的模糊测试和限流来保证。安全方面通过仓库级和目录级的权限控制,并在评审工具
Antique 中加入复杂的语义审批。日常维护则由一组基于 Claude Tag
创建的专门巡检实例负责,内部戏称它们为
superfans,每个实例只负责一个组件,比如
scion-daemon、scion-cache 或 Antique
合并队列的健康状况。
Anthropic 在博客最后也坦诚了 Scion 的定位与局限:它是沿着 Google Piper 和 Meta Sapling 的路线发展出来的一套系统,并非用来取代通用 git,只在超大型单体库中才可能带来好处,并依赖于远超普通公司的内部 token 预算,因此并不打算开源为一个产品。对外而言,它给业界带来的启发主要在于几个架构层面的思路:git 服务端不必与客户端同构、把重计算放到服务端 RPC 里、拉取时可以使用不汇报本地状态的新协商协议,以及把少拉历史的浅克隆与少拉目录的稀疏检出更好地组合起来。
博客发出去以后,社区的第一反应是:这不就是把 SVN、Perforce 或 Meta 开源的 Mononoke 又发明了一遍吗?Scion 和 SVN/Perforce 只是看上去都是服务端集中,但底层的数据模型和水平扩展能力非常不一样。但是它的核心数据模型确实和 Meta 开源的 Mononoke (Bonsai) 非常接近。因为第一版博客没有提到 Mononoke,前 Meta 工程师 Rain 连发了第一篇、第二篇文章来质疑 Anthropic 没有提到 Mononoke 这个署名,并在 Hacker News 的讨论串上面展开了争论。10月15日,Anthropic 补充了脚注点名致谢了 Mononoke 和 Bonsai。
这更多是一个署名问题,而非代码抄袭或开源许可证违规。至于当初是否有意漏署,我们没法独立验证。但它至少提示了一个合理的解释:AI 之所以能快速重造一套底层系统,很可能正是因为前人已经把成熟的设计开源出来、又进了模型的训练集。
对普通工程团队的研发流水线而言,第一个应该放弃的想法是自己去实现一个版本控制系统。Anthropic 的对抗建立在百 GB 的历史库、每天 2,500 万次检出、30,000 次合入和远超一般公司的内部 token 预算上。对大多数团队来说,就算自己的仓库已经变慢,只要先把 Git 自带的三个减负开关配好——在 CI 和 agent 里只拉最近的一两层提交(浅克隆),先拉历史骨架、略过大文件(部分克隆),只把当前目录拉到本地(稀疏检出)——就能吃掉绝大部分痛点。在榨干这些原生工具前,自研版本控制只是在为不存在的规模买单。
在抛弃造轮子以后,这次重构里立刻能拿走的工程判断有三个,分别关于流程、人和账本。
第一,检查研发流程中默认用户是人的隐含假设。你不用等到日均三万次合入才开始优化,当流水线接入高频运行的 agent 时,每次任务全量拉取仓库的 CI 脚本、基于本地遍历提交图查元信息的周边工具、以及让所有提交排成一队等待测试完成的串行 merge queue 都会相继成为瓶颈。把一部分重测试从合入前移到合入后、部署前,并配置自动二分定位和回滚管线,往往比死抠单次测试几秒耗时更有用。
第二,把人的精力从逐行审语法转向守住意图和架构护栏。防止 agent 把老代码里的坏味道继续扩散,也别迷信 agent 之间的对抗式审查;人类工程师负责看清业务意图和模块边界,对模型过度工程化果断说不,同时把确定性仿真测试、目录级权限与自动回滚建扎实。
第三,重算老旧工具的修补与重写账本,但对开源先例保持敬意。要是内部老系统靠打补丁能买到的平稳窗口越来越短,而成熟的架构先例已经公开摆在社区里,抽两三个人借助模型花几周重写一套精简系统,这笔经济账现在完全算得平;只是动手时心里要清楚,省下的时间一半来自模型能力,另一半来自前人留在阳光下的开源设计。