3 天 1531 star:walgit 把 Git 服务器变成一个二进制,仓库直接扔进 S3

你第一次自建 Git 托管时,会踩同一个坑:GitLab 装完一个虚拟机,内存先吃 4G;Gitea 轻一点,但身后照样拖着 SQLite + 一个要盯的进程;真到了上百人的团队,你开始聊主从、聊备份、聊"那个节点挂了怎么办"。
全世界的自建 Git 都是这么长大的——直到有个东西说:为什么服务器要有状态?
walgit,三天 1531 star。它把整个 Git 服务器压缩成一个 Rust 二进制,后端只挂一个 S3/GCS 桶。没有数据库、没有主节点、没有任何"丢不起"的本地状态。桶就是仓库,磁盘只是缓存,每一台跑它的机器都可以随手扔掉。
一句话看懂它在反什么
所有自建 Git 都默认一个前提:仓库必须住在服务器上。为了这份"住",你得配数据库、做主从、管备份、应付扩容。
walgit 把前提反过来:仓库住在对象存储里,服务器只是个"读档员"。你要做的就三件事——起一个二进制,指向一个桶,完事。
|
|
跑起来,然后 push 一个新名字——仓库自动创建。就这样。
它凭什么敢说"没有状态"?核心是 WAL + CAS
这才是值得掰开看的地方。你可能会想:把 git 仓库放对象存储,这不就是"把仓库扔网盘上"吗?那早有人试过,全死了——因为 git 的 packfile 是几 GB 的随机读,走网络文件系统(NFS)延迟直接爆炸,GitHub 当年就是被这个教训逼得上了 Spokes(本地 NVMe + 三阶段复制 + 一堆"宠物服务器")。
walgit 抄的是 Cursor 那篇 Git at any scale(内部叫 Continuity)的架构,但改成了能在比仓库还小的机器上跑。核心就两点:
1. 写入提前日志(WAL)进对象存储,而且不可变。
一次 push 不是直接改仓库文件,而是写成一个不可变对象扔进桶里。只有当一份极小的 manifest 被用 compare-and-swap(CAS)重写后,这次 push 才"可见"。
2. 这个 CAS 就是共识,没有选举、没有 quorum。
任何一台实例都能接收 push,但两个同时 push 的实例不可能都赢——manifest 的 CAS 保证只有一个成功。这比传统的主从简单太多:不需要选主,不需要同步协议,对象存储自带的"条件写"就是所有协调。

读的时候,每台实例先做一次"条件 GET"问桶"有没有变化"(通常返回 304),有变化才拉,没有就用本地缓存。所以读一致性不需要任何协调——每个读都先问一下源头。这就是它说的"没有 eventually,没有最终一致"。
一个反常识的点:仓库可以比机器大
传统 git 托管里,服务器必须能装下仓库。walgit 打破了这条:它做了个 remote reader——refs 和 commit/tree 留在本地,blob 留在桶里,用 HTTP range 请求按需拉。再加 history pack(小机器的 commit 历史打包)+ bundle-uri(把克隆流量整个甩给 CDN 当静态文件发)。
结果是:一台 2G 内存的小机器,可以托管一个本身有 50G pack 的 monorepo。克隆时新用户直接从 CDN 拿 bundle,服务器只补差额。这是传统方案给不了的能力——过去你要么上大机器,要么拆仓库。
和主流方案横向对比
| 方案 | 后端状态 | 数据库 | 主从 | 多实例 | 仓库 > 机器 |
|---|---|---|---|---|---|
| GitLab | 全在服务器 | PostgreSQL + Redis | 要 | 麻烦 | 不可能 |
| Gitea | 服务器 + SQLite/MySQL | 要 | 要 | 麻烦 | 不可能 |
| GitHub Enterprise | 本地 NVMe + 三阶段复制 | 要 | 要(Spokes) | 复杂 | 不可能 |
| walgit | 对象存储 | 无 | 无 | 加一台机器就行 | 可以 |
你发现区别没:别人用数据库管"仓库在哪台机器上",walgit 干脆让仓库不存在于任何一台机器上。“元数据在哪"这个问题,被它直接删掉了。
上手(真实可跑)
|
|
它还带了个一键装机脚本——install.sh 会在你开发者机器上装好 token 和 git 凭证助手,一条命令,幂等。
丑话说前头
这套设计不是没有代价,得诚实说:
- 对象存储是单点:桶挂了全挂。它把可靠性的锅全部甩给了你的存储厂商——AWS/GCS 靠得住,但 MinIO 自托管那部分责任又回到你身上。
- 延迟敏感:每个读都要先"条件 GET"问桶,网络不好时第一个字节会慢。它自己也专门写了 ROUNDTRIPS 文档讲怎么减往返。
- 很新:仓库刚 3 天,193 到 1531 star 只用了 72 小时,但只有 1 个 commit 起步、还是 tobi 一个人在做。上生产要谨慎,PR 欢迎。
- 生态为零:没有 CI 集成、没有 MR/PR 审批流(只有基础的 push policy/webhook)——它定位是"Git 托管”,不是"GitHub 全家桶"。
值得关注的点
walgit 最值得抄的不是 git 本身,而是**“把状态从服务端挪到对象存储 + 用 CAS 当共识”**这个思路。S3 的条件写(conditional put)21 个月前才发布,之后整个行业在往"解耦存储"狂奔——PicoMQ、Celld、SlateDB 都是这个方向。
而 git 托管,可能是被这个范式改造得最彻底的一个:当你的"服务器"只剩一层可丢弃的缓存,扩容、容灾、备份这些问题,一夜之间全都消失了。
Git 本来就是分布式的。walgit 只是把这份分布式,贯彻到了托管它的服务器上。
搬砖程序员带你飞,专注 Golang / AI / 后端。每天一篇,讲清楚一个技术真相。
