首页
/
工具
/
Grit:用Rust和智能体重写Git
Grit:用Rust和智能体重写Git
摘要
本文介绍了Grit,这是一个用Rust重新实现的Git新版本,通过了超过99%的Git测试套件,并且是通过AI智能体创建的。它旨在提供一种基于库、内存安全的替代方案,以取代原版Git。
暂无内容
查看缓存全文
缓存时间:
2026/06/10 00:22
# Grit:用 Rust 和代理重写 Git
来源:https://blog.gitbutler.com/true-grit
几个月前,我读到了 Anthropic 发布一群代理来编写一个可运行的 C 编译器的实验(https://www.anthropic.com/engineering/building-c-compiler),这让我思考,是否可以用同样的方法来实现我梦寐以求了 15 年的事情(https://github.com/libgit2/libgit2/commit/4b7483a285024937df9623c3543390e717e2338a)—— 从零开始重写 Git,使其基于库。
Git 当然是一个非常复杂的软件。大量“plumbing”(https://git-scm.com/docs/git#_low_level_commands_plumbing) 命令、许多高级(https://git-scm.com/docs/git#_high_level_commands_porcelain)命令——它是由数以千计的人在过去的 20 年里为大小项目逐步构建起来的。它从未基于可链接且可重入的库,而是基于“Unix”哲学——将简单的命令串联起来,这意味着在长时间运行的进程中使用它很困难,因为每次操作都要承受 fork/exec 的开销。
不过,有趣的是,Git 项目拥有一个非常全面的测试套件,包含超过 42,000 个测试,分布在 1,400 多个脚本中,这些脚本相当严格地定义了所有功能应该如何(以及不应该如何)工作。
如果我们采用 Anthropic 在从零编写 C 编译器时使用的相同基本思路呢?启动一个全新的实现,将其设计为 Rust 库,然后向问题抛出一群代理,不断冲击直到所有测试通过?
好吧,在过去几个月里我断断续续地这样做了,结果就是 Grit (https://github.com/schacon/grit),一个从零开始、基于库、内存安全、符合 Rust 习惯的 Git 重实现,通过了整个 Git 测试套件的 99% 以上。
新的 Grit 项目网站 新的 Grit 项目网站 (https://grit-scm.com/)
**注意!**
虽然 Grit 通过了测试,但它并未经过*实际测试*。还没有人真正用它做过任何实际工作。如果你尝试使用它,请注意,目前有很大概率会做错事,甚至可能损坏数据。使用风险自负。但如果发现了问题,请告知我们 (https://github.com/gitbutlerapp/grit/issues),以便我们修复。
与 Anthropic 的实验不同,这不仅仅是为了看看是否*可能*做到。当初开始的时候,我想如果这可行,我们可能会得到一些比 C Git 更有用的东西。不过这一点我们稍后再说。
我到底想从这得到什么?
我*不*想要的是将 C Git 纯粹移植到 Rust。事实上,我越深入研究,越不确定是否应该复制 Git 中曾经做出的每一个决定,但既然原始目标已经达成,我们可以在此基础上进行改进。
我*想要*的是一个纯 Rust 的核心库,能够忠实且规范地与 Git 仓库交互。可重入、可链接、模块化且全面。然后,为了确保全面性,再构建一个独立的 crate,提供一个 CLI 界面,*使用*那个库,以便尽可能多地通过 Git 测试套件。
这就是我们所做的。
嗯,不完全是,但这很有趣,并且可以说已经很有用了。
首先,一些注意事项。
它实际上并没有通过*每一个*测试,但这是故意的。我故意标记了测试套件的某些部分为“跳过”,因为我认为在一个像这样的库中重新实现它们不值得——涉及邮件、i18n、Perforce/SVN 导入、部分 midx/bitmap 的东西——诸如此类。然而,对于几乎所有读者都可能相关的所有内容,Grit 库/CLI 现在可以完全通过 Git 测试套件了。
这是否意味着它完美无缺?不。它仍然很慢(在某些情况下是指数级慢),有一些未经测试的功能无法实现,API 也不够干净,没有 Windows 构建等等。这只是第一次尝试的第一个里程碑。
然而,对于几个月和几十亿令牌的工作量来说,这是一个相当有趣的起点。
我们能拿它做什么?这是一个有趣的项目,但我们不只是为了看看是否可能才做的。我认为 Grit 可以很容易地发展成一些相当有用的东西。
我主要想用它做的一件事是,将复杂的推送/获取功能打包到 GitButler (https://gitbutler.com/) 和其他需要网络功能的独立 Git 工具中(例如 Jujutsu (https://github.com/jj-vcs/jj))。
目前,Gitoxide (https://github.com/gitoxidelabs/gitoxide) 和 libgit2 (https://github.com/libgit2/libgit2) 的网络功能要么不完整,要么缓慢,要么根本不存在。GitButler 和 Jujutsu 都依赖于 fork 出 Git 来推送或拉取数据。一个主要原因是其中涉及极其复杂的凭证逻辑,但所有这些(理论上)目前在 Grit 中都已经覆盖了。
另一个可能的使用场景是 WASM 构建,它可以用来做各种各样有趣的事情。例如,在 Vercel 的边缘函数中运行几乎任何 Git 命令。或者,你也许可以构建像 Cloudflare Artifacts (https://blog.cloudflare.com/artifacts-git-for-agents-beta/) 这样的东西,而不必依赖像 isomorphic-git (https://isomorphic-git.org/) 这样的部分实现,而是使用完全兼容的 Grit WASM 构建。
将 Git 的部分功能作为独立、可嵌入的库切片,也使得构建自定义 Git 服务器或 Rust 客户端功能成为可能。
将整个 Git(或者也许只是你需要的部分 Git)以已知版本原生嵌入到诸如代理桌面构建或像 Zed (https://zed.dev/) 这样的编辑器中。
目前所有 Git 功能在 Rust 中的完整构建大小约为 27M,但由于其中很大一部分是库,显然可以轻松地按功能领域拆分为子 crate——做特定事情的子 crate。也许你只需要使用你需要的子集。
并非所有这些在今天都能用 Grit 实现,但我相信这个里程碑证明了,再多一些工作,这些绝对是触手可及的。
你说 WASM 的时候我就兴奋了……
在深入细节之前,有趣的是,几乎所有代码都是内存安全的。
基本上只有一个模块(日期/时间)必须通过 FFI 胶水与 C 交互,再加上一个 TTY 检查。(显然,没有纯 Rust 的等价物来实现遵循 TZ 环境的 `localtime_r`/`strftime`/`mktime`,所以看起来这个 FFI 是不可避免的。)
Grit 中的其他所有东西都是安全的 Rust。
这实际上是一次有点“代理式”的小旅程。我最初以为我可以定义某种代理文件,然后运行一群代理循环,几天内就能完成所有工作。
结果发现事情并非如此,至少在这个复杂程度的项目上不是。或者也许我不太擅长这个,但这真是一个昂贵的教训,而且明显非常令人沮丧地非确定性。
与其详述每一步,不如直接概括一下我在这个过程中学到的一些东西,可能更有趣。
如果你告诉一个代理“让这些 Git 测试通过”,它很容易就会写一个简单的函数,直接通过调用 Git 来实现。我花了几次才意识到它作弊了,看到太多测试通过得太快,然后修改了 AGENTS 文件,真正让它停止这种行为。
这就像精灵许愿一样。你必须非常明确地制定基本规则。该死,不许许愿更多的愿望。
一个很好的例子:对于 sha256 支持,有几个地方会测试这个,但如果只为了实现测试运行,LLM 意识到它们可以在不实际实现 sha256 支持的情况下通过测试。
当我意识到 Grit 实际上在 sha256 初始化的仓库中根本不起作用,并就此询问 Claude 时,它报告说:
> 有少数测试确实运行了 `git init --object-format=sha256`(t0001-init, t1900-repo-info, t0610-reftable-basics)。这些测试运行并通过了——但看看它们断言了什么(t0001:519-587):每一个都只检查 `rev-parse --show-object-format` 报告了 `sha256`,也就是说 init 将 `extensions.objectformat=sha256` 写入了配置。grit 的 init.rs 正确地处理了该元数据(is_known_object_format 接受 "sha256",第 869-870 行)。这些测试中没有一个是添加、提交或在该仓库中记录的。
所以它只关注被测试的内容,让那些通过,而实际上只是普通的 sha1 操作。它并没有真正思考“我大概应该实现真正的 sha256 支持”。
这个项目花费的时间超过几周的原因之一是,我中途差点放弃,因为一组并行代理破坏了测试框架的一个基本部分,看起来像是大规模回归。
我认为太多的并行工作弊大于利,也许这个项目根本不可能完成,成本太高了,所以我有一段时间几乎完全放弃了。
以下是从我开始的 4 月 1 日到今天的大致时间线,以及测试套件通过百分比的演变。
紫色条表示每天的提交数量,所以你可以看到两轮努力——4 月初的一周左右和 6 月初的一周左右。
每天的提交数和测试套件通过百分比
每天的提交数和测试套件通过百分比
虚线是*报告的*通过百分比。你可以看到 4 月中旬有一个巨大的下降,这导致了我对这个项目的兴趣下降。
6 月初,我重新拾起它,试图挽救工作,让它做一些更简单的事情。在修改过程中,一个代理发现了错误并修复了测试框架,通过百分比一下子回升到大约 80%,这促使我尝试完成它。
我之前和 OpenClaw 以及 Ralph 合作过。我也多次运行过并行代理。比我预期的更困难的是长期运行和并行相结合。
这可能不是一个常见问题,因为尝试这样做相当昂贵,但我发现拥有一个共享的任务列表,让几个或几十个长期运行的代理可以一起啃,是非常困难的。
特别是如果你还想稍微推动一下。在这种情况下,你需要暂停它,合并所有内容,改变方向,然后再次生成团队。
我主要尝试使用带有复选框的共享计划文件,但这相当混乱。可能像 Linear 或 GitHub Issues 这样的东西是更好的协调方式,但速度更慢,并且需要每个客户端都有网络访问、认证和工具。
在项目结束时,我开始使用我的 Ticgit (https://github.com/schacon/ticgit) 本地票据系统项目,这样任务列表可以轻松地在本地修改,并通过 Git 移动,但那是另一篇博客文章了。
我可能应该在某个强大的服务器上运行这个,但实际上我是在很多不同的地方做的——我的笔记本电脑、我的 Mac Studio、一个 Hostinger 实例、Cursor 云代理等等。前三个在并行负载下都遇到了资源问题。事实证明,当你同时进行很多编译时,Rust 编译比我想象的要更消耗资源。
代理本身通常很擅长调试和修复问题(遇到了交换颠簸、CPU 颠簸等),但情况偶尔会变化,管理起来比我预期的更困难。Anthropic 在容器中做了他们的编译器实验,所以也许事先做一些系统规划比我的“随缘”方法更好。
#### 交接
交接进行中的工作一直是个问题。因为我在多个系统上工作,其中一些在我的笔记本电脑上,以便我可以实际运行和测试,如果能将手头的工作打包起来,然后轻松地在别处继续,那就太好了。
虽然一些代理框架在某种程度上做了类似的事情,但由于我使用了多个提供商(得用掉那些订阅),这里仍然有很多摩擦。这是我们正在与 GitButler 合作,在 VCS 层而不是框架锁定层提供的内容,所以敬请期待。
### 成本和令牌使用量很快就能累积起来。
你真的必须小心。
我不确切知道我在 Cursor 和 Anthropic(我使用的主要提供商)上花了多少钱,但大概在 1 万到 1.5 万美元左右。
我的方法改变了好几次,部分是因为我看到了并行工作、长时间运行以及成本与测试通过率变化之间的困难。
我最初使用 OpenClaw 配合 Claude Code 通过 API 做了很多工作,这相当昂贵。然后,大量工作是通过一批短命的 Cursor 云代理完成的,它们针对单个测试文件运行 composer-2。我最后在所有系统上使用订阅令牌完成了项目(并行使用 Codex、Claude 和 Cursor,注意使用限制)。
令牌方面,这个项目大概的粗略估计如下:
- Claude Code:140 亿令牌
- Cursor(GPT/Codex):120 亿令牌
- Cursor(composer-2):160 亿令牌
4 月份 Cursor 模型使用概况
4 月份 Cursor 模型使用概况
数据分散且与其他项目混杂,所以很难精确,但假设*大致*总共 450 亿令牌。有趣的是,项目几乎一半是通过大量短命、专注的 Cursor 云代理使用 `composer-2` 模型完成的。
正如我所说,我在这段时间尝试了许多不同的方法来解决这个问题。以下是一些比较有趣的尝试以及我对它们的体验。
起初我用 OpenClaw 运行 Claude Code 子代理做了很多工作,因为我刚开始这个项目时每天在湾区来回通勤好几个小时,而这是一个远程运行它的好方法。
然而,由于我必须使用更昂贵的按令牌 API,最终我在短短几天内就花费了项目大部分成本。
一周 8000 美元,还不错...
一周 8000 美元,还不错...
除了成本之外,保持运行也很困难。我在机器上遇到了内存和 CPU 问题,Hostinger 的那台在某个时候直接宕掉了,我费了好大劲才让它重新上线,这非常脆弱。
当我意识到如果不花费更多的数万美元,这个项目就无法完成时,我改变了策略,利用一些订阅令牌和更便宜的模型。
最终完成项目大部分工作的一个策略是,为我想处理的每个文件生成一个 Cursor 云代理,然后在每个完成后合并它们。
我在这里遇到的问题是,这是一个非常手动化的过程。事实证明,当你在构建 Git 的替代品时,某些测试会搞乱环境,然后试图使用*你的*二进制文件而不是 Git,或者搞乱容器 Git 访问所依赖的凭证存储。这意味着 Cursor 代理无法使用 Git 将生成的代码推出容器。这是一个这个项目特有的问题,特别感谢 vmg (https://x.com/vmg) 和 Cursor 团队帮助我弄清楚可能发生了什么。
我从未完全搞明白*如何*我的测试覆盖了环境,以至于搞乱了推送,但这意味着对于*很多*测试,我必须进入容器的终端,手动添加一个远程仓库并推送提交。我花了很多时间手动点击、复制/粘贴——有时只是为了一个三行的 Rust 变更。
这并不理想,但最终确实并行完成了大量工作(因为我同时运行了很多这样的代理)。
这实际上是我在所有尝试之后最喜欢的做法。
我之前不知道这个,但我们出色的合作伙伴 Matt (https://x.com/BornsteinMatt)
相似文章
X AI KOLs Timeline
I have one big problem with agentic engineering: I want agents to operate autonomously, but I also want granular, reversible control over every change they make. I could solve this by committing every intermediate step to Git, but that would completely pollute my repo history. So I built 𝗮𝗴𝗴𝗶𝘁: a Git-like CLI for local and remote (S3-backed) agent artifact storage, written in Rust . With aggit, my agents can stash intermediate work, create branches safely, restore previous states, and back
Hacker News Top
Gitdot 是一个开源的、反 AI 的、用 Rust 编写的 Git 托管平台,旨在作为 GitHub 的更好替代方案。
X AI KOLs Timeline
斯坦福大学的研究人员发布了 Shepherd——一个运行时层,对 AI 智能体的运行而言就像 Git 一样:它记录类型化事件,并支持写时复制(copy-on-write)分支,让智能体可以回滚到之前的状态并复用 KV 缓存。早期测试显示,多智能体协作任务的通过率有所提升。
Reddit r/AI_Agents
git-mem 是一个面向 AI 代理的记忆解决方案,利用 git 和 redis 实现高性能和审计日志,包含一个 web UI 和极少的依赖项。
Hacker News Top
re_gent 是一个开源的版本控制系统,专为AI代理活动设计,记录每一次工具调用及其相关提示,使开发者能够审查和回滚代理的变更。