---
title: "Aspen：让智能体提交的规模超出 Git 原本的设计"
description: "一个开源的 Git 服务器，面向数百个智能体同时推送的代码库，沿用了 OpenAI 为 Pando 描述的设计。客户端使用普通的 Git，pack 存放在对象存储中，分支存放在 Postgres 中。"
url: "https://reasonmachines.com/zh-hans/blog/aspen"
section: "简体中文"
---

# Aspen：让智能体提交的规模超出 Git 原本的设计

_一个开源的 Git 服务器，面向数百个智能体同时推送的代码库，沿用了 OpenAI 为 Pando 描述的设计。客户端使用普通的 Git，pack 存放在对象存储中，分支存放在 Postgres 中。_

作者：Reason

2026年11月5日

Git 是为人设计的。一个人每天推送几次。智能体每隔几分钟就推送一次，一个运行几百个智能体的团队会把一个代码库变成消防水龙：数百个分支同时变化，每次推送之后 CI 都要 fetch 一次。

传统的 Git 服务器跟不上。它把对一个代码库的所有推送都放进同一个队列，所以你分支上的推送要等其他所有人的推送；它还要为每一次 clone 和 fetch 新建一个 pack，为每个客户端重新压缩同样的历史。pack 是 Git 用来批量传输对象（文件、目录和提交）的文件格式。服务器的工作量随客户端数量增长，而不是随新代码的数量增长。

### 一千个写入者，两台服务器

每个方块是一个推送十次提交的智能体。读者 fetch 到全部十次后，它会变成蓝色。示意图，时间经过压缩。

写入者 2501000播放速度 10×20×40×

传统 Git 服务器就绪

0 秒模拟–推送 → fetch0已完成的写入者

Aspen就绪

0 秒模拟–推送 → fetch0已完成的写入者

未开始在服务器队列中等待推送中十次全部已 fetch

这是一个玩具模型，不是基准测试。传统服务器在同一个代码库里依次处理每一次推送，并在同一台机器上为每次 fetch 构建 pack，所以一旦到达速度超过它的处理速度，队列就会变长。Aspen 用各自的 compare-and-swap 移动每个分支，并从已存储的 pack 中响应 fetch，所以写入者以自己推送的速度完成。

OpenAI 在他们的单体仓库上撞到了这堵墙，并在《Scaling Git at OpenAI》中写下了他们如何越过它。他们的答案是 Pando，一个内部的 Git 后端。[1](#ref-1)我们很喜欢这个设计，于是决定公开地把它做出来。今天我们发布 [Aspen](https://github.com/reason-machines/aspen)，一个任何人都可以运行的、独立的开源实现，采用 Apache License 2.0。[2](#ref-2)

Aspen 通过 HTTPS 和 SSH 使用普通的 Git，所以客户端什么都不用变：`git push` 和 `git clone` 照常工作。所有区别都在服务器端。

## 我们放弃的两件事

Git 服务器需要在两个方向上扩展：许多写入者推送到不同的分支，许多读者 fetch 同一份历史。沿用 Pando 的做法，Aspen 放弃了大多数 Git 服务器视为神圣的两项保证。

**所有分支的同一时刻快照**每个分支都是 Postgres 中的一串版本，各自独立变化。一次推送先上传它的 pack，然后在单独一行上用一次 compare-and-swap 移动它的分支：“把这个分支从提交 A 移到提交 B，前提是它仍然指向 A。”推送到不同分支的操作从不互相等待。对同一个分支的两次推送在那一行上竞争，其中一个干净利落地胜出；另一个会收到 Git 常见的“fetch first”，然后 rebase。代价是：同时查看多个分支的读者，看到的每个分支可能处于略微不同的时刻。智能体并不在意。

**为每个客户端定制的 pack**Aspen 从不解包推送。它检查 pack，补上 Git 因为服务器已经拥有而省略的对象，然后按收到时的原样存入对象存储（S3、GCS、Azure Blob 或普通目录）。有人 fetch 时，Aspen 算出哪些已存储的 pack 包含对方缺少的内容并直接流式发送，不做任何重新压缩。它还可以发放签名 URL，让客户端直接从 CDN 下载这些 pack。

### 一次推送，然后一次 fetch

一台无状态服务器，位于标准 Git 和两个存储之间。两条路径上都不会构建 pack。

推送fetch分支行pack

Postgres 为每个分支保存一行，对象存储保存按推送原样存放的 pack。推送写入一个 pack 并替换一行；fetch 读取一行并发送已经存在的 pack。点击某一步即可重放。

## 任何人都能推送的画布

为了把 Aspen 展示给人看，而不是给压测工具看，我们把它放在了 [place.reasonmachines.com](https://place.reasonmachines.com) 后面：一个无需登录的 64 × 64 像素共享画布。每个像素都是 Git 代码库中的一个文件，点击一个格子就是向 Aspen 的一次提交和一次推送。一个机器人把所有人的分支合并到 `main`，而 `main` 会镜像到 [GitHub](https://github.com/reason-machines/place-canvas)，那里的 README 会实时显示画布。

你也可以在终端里画：clone 下来，修改一个格子的文件，然后 `git push`。或者按页面上的 **Copy prompt**，把提示词交给 Claude Code、Codex 或任何编程智能体；它会问你想画什么、画在哪里，给你看预览，等你同意后再推送。

### 画布 已暂停

每个像素都是一个文件，每次点击都是推送到 Aspen 的一次提交，无论来自人还是智能体。这张图每两秒刷新一次。

git clone --depth=1 https://place.reasonmachines.com/canvas.git
cd canvas && printf '#3690ea\n' > tiles/10_20.txt
git add tiles && git commit -m paint && git push origin HEAD:paint/you

推送进入 paint/ 分支，由机器人合并到 main。规则和调色板在画布的 TILES.md 中；它的 main 镜像到 [GitHub](https://github.com/reason-machines/place-canvas).

## 推送只看到主干

推送时，普通的服务器会先列出它拥有的每个分支，这样你的客户端就能跳过服务器已经有的对象。如果有一百万个分支，光是这个列表就非常庞大；而且客户端构建的 pack 取决于恰好被列出的那些分支，别人无法复用。

Aspen 只列出主干分支。于是你的推送会包含主干之后的全部内容，任何拥有主干的人都能用这一个 pack fetch 你的分支。推送会稍大一些；无论有多少个分支，这段对话的大小都不变。唯一能看到的区别是：`git push --force` 和 `--delete` 需要额外加上 `-o force`.

## 压缩合并

如果每次推送都保存一个小 pack，落后一天的客户端就需要成千上万个。所以 Aspen 在后台以每次十六个、分层级的方式合并 pack，就像日志结构合并树压缩它的文件一样。全新的 clone 拿到少数几个大 pack，几乎最新的客户端拿到少数几个小 pack。

浅 clone 有自己的快速路径，因为 CI 默认使用 `--depth=1` 进行 fetch。Aspen 为分支顶端只构建一次 depth-1 pack，然后发给每一个请求它的 CI 任务。

### 作为跳表的层级

每一条是一个 pack。压缩合并让 pack 保持四种大小，fetch 在客户端和主干之间的每一步都取能放下的最大 pack。

客户端已有v0

计划中的 pack0

每次推送一个 pack0

客户端已有发送中已发送已存储，不需要

一个落后数千个版本的客户端，拿到的是几十个 pack 而不是几千个：中间长段用大 pack，只有两端用小 pack。沿着历史拖动即可移动客户端。

## 有多快

对智能体而言，重要的数字是每秒推送到同一个代码库的次数，而且每次推送都要安全存储后才算数。Cursor 公布了其 Git 服务器 Origin 的数字：在 S3 Standard 上每秒最多 120 次推送，在更快的 S3 Express One Zone 上超过 300 次，且对一个代码库的每次推送都经过同一份日志。[3](#ref-3)Aspen 只对同一分支的推送排序，所以没有那种按代码库计的上限。²

在一台 8 核服务器、S3 Standard 和 4 核 Postgres 上，通过 Aspen 的分支 URL 推送到 git.git，Aspen 在五分钟内保持每秒 567 次推送，没有错误。在 Git 打印“ok”之前，每次推送都已写入 S3 和 Postgres；推送中位数为 208 毫秒，99 分位为 314 毫秒。另一个客户端在推送被确认后 30 毫秒（中位数）就能看到它。

OpenAI 没有公布 Pando 的推送速率。它报告的是相对其旧系统的结果：推送延迟中位数下降近 80%，用少量 CPU 核心每天提供一 PB 的 Git 数据，clone 能跑满 10 Gbps 的链路。[1](#ref-1)Aspen 沿用的是 Pando 的设计，所以与它诚实的比较是数字的形态：彼此不等待的推送，以及从已存储的 pack 而非重新构建的 pack 中响应的 fetch。

合入 main 是另一类数字。每次合入都建立在前一次之上，所以单独的合入只能一次一个进行；这样做时 Aspen 每秒大约处理 4 次，限制来自往返时间而不是负载。Aspen 还有一个服务端合并队列，可以在对 main 的一次更新中合入多个 PR，每个 PR 仍是独立的提交；测出数字后我们会公布。这些数字都不包括 CI。

### 每秒推送到同一个代码库的次数

每次推送在被确认之前都已持久化。Cursor 的数字为其公布值；Aspen 的数字是我们的测量结果。

Cursor Origin，S3 Standard

120

Cursor Origin，S3 Express

300+

Aspen，S3 Standard

567¹

Aspen：一台 8 核服务器、S3 Standard 和 4 核 Postgres，通过 Aspen 的分支 URL 推送到 git.git，持续五分钟。Cursor：在其自身单体仓库上的复制集群，文中没有给出该仓库的规模。
¹ 每秒 567 次是 git.git（约 4,500 个文件、7.5 万次提交）通过 Aspen 的分支专用 URL 推送得到的。
² 随着代码库变大，每次推送的成本仍会增加，所以目前非常大的单体仓库速率会更低；这正是我们现在要解决的。

## 开源，而且还很早期

代码在 [GitHub](https://github.com/reason-machines/aspen).`aspen dev` 上。用 SQLite 和本地目录就能在你的笔记本上运行服务器；团队使用的话有 Docker Compose 栈、Helm chart，以及适用于 AWS、Google Cloud、Azure 和 Hetzner 的 Terraform。

只有在与标准 Git 结果一致的地方，我们才信任 Aspen。差分测试套件把随机的推送、删除和竞争同时重放到 Aspen 和 Git 自己的服务器上，并要求结果完全相同；每天晚上，从 2.30 到最新版的 Git 以及 JGit 都会对它运行；模糊测试和一个在推送中途杀掉服务器的混沌测试套件也同时运行。和 Pando 一样，Aspen 主要由智能体构建：一个 Reason 用了四天、151 个合并的拉取请求，把它从第一次提交带到了公开发布。[1](#ref-1)

它还处于预览前阶段（pre-alpha）。Aspen 只负责 Git 这一部分，没有 Web 界面，也还不支持部分 clone、SHA-256 代码库或 RSA SSH 密钥。如果你让智能体在同一个代码库上工作，欢迎试用、把它搞坏，然后在 GitHub 上告诉我们。

## 参考资料

<a id="ref-1"></a>
\[1\] OpenAI. Scaling Git at OpenAI, 2026. 介绍 OpenAI 的 Git 后端 Pando：按分支的 ref 版本、只通告主干的推送、通过 packfile URI 复用 pack，以及类似 LSM 的压缩合并。Aspen 是该设计的独立实现，与 OpenAI 无关。[文章](https://openai.com/index/scaling-git-at-openai/).

<a id="ref-2"></a>
\[2\] Reason Machines. Aspen：面向智能体规模代码库的开源 Git 服务器，Apache License 2.0。[仓库](https://github.com/reason-machines/aspen)，在线演示位于 [place.reasonmachines.com](https://place.reasonmachines.com).

<a id="ref-3"></a>
\[3\] Cursor. Git at any scale, 2026年8月. Origin 在 S3 Standard 上维持“每秒最多 120 次推送”，在 S3 Express One Zone 上“每秒超过 300 次推送”，只有在推送写入预写日志后才确认。[文章](https://cursor.com/blog/git-at-any-scale).
