Oak 想给 AI agent 换掉 git,我天天用 Claude Code 改代码,先说说 git 到底卡在哪

cover

哈喽,我是飞飞。

这两天 Hacker News 上有个东西在转,叫 Oak。一句话介绍:专门给 AI agent 用的版本控制,想在 agent 这个场景里把 git 换掉。我看到它,脑子里没先冒出「这玩意好不好用」,反倒是手已经摸到了我每天那个真实的烦:我让 Claude Code 改一个任务,它一秒钟改十几处文件,git 那边的提交记录瞬间就乱成一锅粥。

所以这篇不打算给你评测 Oak 有多神。我想借它这件事,把一个憋了挺久的问题摊开讲清楚:git 是给人用的,agent 来了之后到底哪儿开始扛不住,以及最后我自己换不换。

git 是给「一天提交几次的人」设计的

先把话说在前头。我不是来唱衰 git 的,它是我每天干活的地基,这点不会变。

但你想想 git 当初是为谁设计的。给 Linux 内核那帮维护者用的,一个人写一段、想清楚了、攒成一个有意义的改动,写一句话说明白「我这次干了啥」,提交。一天提交几次顶天了,每个 commit 都是人经过脑子的一个完整想法。这套模型的核心假设是:提交的人,是个会停下来思考、会给改动起名字的人类。

agent 不是这么干活的。

我让 Claude Code 做一次七千行的 SpringBoot Java 迁到 Kotlin,它在一个任务里来回改的次数,我都数不过来。改一版、跑测试、挂了、读报错、再改、再跑。这个循环它自己能转十几二十轮。要是每一步都老老实实 commit,我的 git 历史里就会塞进来几十个「fix」「update」「try again」这种鬼东西,没一个是人想出来的,全是 agent 自言自语的过程草稿。

这就是 Oak 作者那帮人想戳的第一个点。他们管它叫 commit-message 税。说白了就是:git 逼着你给每个改动起个名字写句话,可 agent 一秒钟蹦十个改动,这个名字根本起不过来,起了也是噪音。

agent 改代码时,git 到底卡在哪几处

光说概念没意思,我把天天踩的几个卡点摆出来,你大概率也遇到过。

一个是提交噪音。agent 跑长任务,你要么忍着让它一路不提交(那万一中间它把代码改炸了,你想回退到某个还能跑的中间态,没有,因为没存档点),要么让它频繁提交(那你的历史就被写成流水账,过两天你自己都看不懂哪个 commit 是真有意义的)。这俩都难受,我至今没找到一个让自己舒服的频率。

再一个是回滚。agent 探索性地改了一大片,结果发现方向不对。这时候你想干净撤回到它动手之前,git 那套工具其实挺笨重,reset、revert、stash 几个命令在脑子里绕,绕错一个就把别的东西也带走了。那次 Kotlin 迁移,有个叫 isLiability 的字段在某个分支里凭空消失了,我盯着报错愣了两秒才反应过来是 agent 在某一轮里把它并进了另一个数据类。这种「它到底在哪一步改坏的」,在一堆 agent 自动提交里翻起来特别费劲。

还有一个最隐蔽,是历史被写乱。git 的历史本来是给人看的,是一个项目的叙事。可你放任 agent 去写这个历史,它写出来的根本不是叙事,是一团草稿纸揉成的废纸团。等你哪天真要靠 git log 去搞清楚一个功能是怎么演化来的,发现根本读不下去。

这几个点,Oak 不是没看见。它给的答案挺干脆:别让 agent 碰你那条给人看的主线。

Oak 把版本控制从里到外重做了一遍

Oak 的做法,我去官方页面和它 GitHub 核了一遍,它没在 git 外面套个壳了事,是从存储层往上重写的。下面这些数字和机制我都对着 oak.space 看过,没核到的我会标出来。

它底层用 BLAKE3 内容哈希。官方原话是,所有东西都按内容寻址,一个文件块的身份就是它的哈希值,同一个文件存两次,只花一次写入。在这之上是内容定义分块,算法叫 FastCDC。翻成大白话就是:它切文件不按固定位置下刀,顺着内容来切。官方举的例子,你在一个 100MB 文件开头插一行,传统做法可能整个文件后面全错位要重存,FastCDC 只让插入点附近那几个块失效,剩下照旧。对 agent 这种一秒改几十处的场景,省下来的开销是实打实的。

数据模型它分四层,Blob、Manifest、Commit、Tree。后端可以选 SQLite,也可以挂在 git 上。

但真正让我觉得它想明白了的,是工作单元那块。它不再把「一次提交」当基本单位,而是拿「一个分支」当工作单元,一个分支对应 agent 的一次会话,再用一段分支描述替代你逐次写的那些提交信息。这就正好接住了上面那个 commit 税的问题:你不用给 agent 的每一步起名字了,整个分支干了件什么事,写一段就行。

它还有个内容寻址的懒挂载,意思是 agent 不用把整个仓库 clone 下来,按需加载,几秒钟就能开始在任意一个仓库里改东西。速度上官方说快照最高比 git 快 95%。这个 95% 我得标清楚:是官方自己宣传的数字,我没看到独立第三方实测复现过,你听个方向就好,别当铁的。官方倒挺克制,专门加了句「速度快是这套设计的副产品,不是我们的卖点」。

目前它是 v0.99.0 公测版,支持 macOS 的 Apple Silicon、Linux 的 x86_64、Windows,curl 或者 cargo 装,Apache-2.0 开源。这些我都核到了。

那到底是 git 不够用了,还是又一个想取代 git 的轮子

这才是最值得吵的地方。

Hacker News 上这类「给 agent 造个 X」的东西每次出来,底下永远有一派人冷笑:给 agent 的 git?那不就是 git 吗。给 agent 的浏览器?那不就是浏览器吗。话糙,但戳到一个真问题:很多所谓的 agent 专用工具,扒开看就是在原来的东西外面挂了个钩子,agent 自己用 git 用得好好的,你这层封装纯属多余。

我得承认这派说得有道理。至少今天,我让 Claude Code 自己跑 git,它命令用得比很多新人都熟。

但反方的反驳也站得住。这类工具作者的核心论点是:让 agent 的每一个动作都直接落进 git,会污染历史、造成巨大开销,所以正确的做法是把 agent 的工作流跟 git 解耦开,agent 先在自己那层折腾,等人确认了、批准了,才落进给人看的那条主线。

你发现没有,吵到这儿,两边其实没那么对立。承认 git 历史会被 agent 写乱,这件事双方都同意。分歧只在于:解决它,要不要动到存储层这么狠。

我的判断偏向中间。git 的提交粒度和历史线性,在 agent 高频改动下确实被撑得难受,这个痛点是真的,不是 Oak 编出来吓唬你换工具的。我天天亲历。但「真到了要换底座」这一步,我现在还迈不过去。

我会不会换,老实说

不会,至少现在不会。理由都挺现实。

一个是迁移成本。我光写文章这一条流水线,就挂着十几个 skill,配图的、查重的、发布的,每一个都是顺着 git 那套规矩磨出来的。底座一换,这些东西大概率得挨个重调,省下的那点提交噪音,换不回我搭进去的那些晚上。这笔账,跟我每次动用 Opus 之前在心里过的那杆秤是同一杆。

再一个是 v0.99.0 这个版本号。它还在公测,我的真实仓库不是拿来给一个 0.99 的版本控制系统当小白鼠的。这倒不是信不过它,任何一个我每天在上面押着代码的工具,我都得等它再稳一阵才敢上。

最让我对 Oak 真有点好感的,是它根本没逼你二选一。它有个 oak export 命令,能把你在它那边的分支历史,原样回放成一个全新的 git 仓库,每个 commit 的作者、邮箱、时间戳都给你保留。这就意味着,哪怕你拿它当 agent 的隔离实验场,最后还是能干干净净地导回 git 给人看。它自己也说得很清楚,Oak 不替你调 AI,你带 Claude Code 也好、Codex 也好、Cursor 也好,那都是你自己的事,它只管版本。

这个姿态我是认的。它没站在「git 已死」的高台上喊口号,而是承认 git 还得用,只是中间那段 agent 自己折腾的过程,git 接不住,它来接。

所以绕一圈我才看明白,这事压根不是「git 够不够用」的二选一。是 agent 来了之后,版本控制被劈成了两段:一段是 agent 自己反复试错的过程,这段确实该有个新东西兜着;另一段是给人看的那条干净主线,这段还是 git 的地盘。Oak 想做的是前面那段,它没要你交出后面那段。

我现在还守着 git,但我会一直盯着 Oak。等它过了 1.0、等有人拿真仓库跑出独立的实测数据,我大概会先拿它当 agent 的草稿层试一试,把人那条主线还留在 git 上。

你呢,你让 agent 改代码的时候,是宁可让它一路别提交、最后自己收尾,还是宁可它一步一个 commit、把历史写成流水账?这两种我都试过,到现在也没拿定主意哪个更不亏。