NEE's Blog

Manyana:基于 CRDT 的版本控制未来

March 23, 2026

本文翻译自 Manyana,原载于 Hacker News。


Bram Cohen(BitTorrent 发明者)最近发布了一个名为 Manyana 的项目,展示了一个关于版本控制未来的一致性愿景——以及一个令人信服的实现理由。

CRDT 与版本控制:迟来的结合

Manyana 的核心理念是使用 CRDT(Conflict-Free Replicated Data Types,无冲突复制数据类型) 来实现版本控制。这个方向在技术上一直被认为是正确的,但因为一些微妙的 UX 问题,至今没有被主流工具采用。

CRDT 的关键特性是:合并永远不会失败。传统意义上不存在”冲突”——关键洞察在于,当两个改动”相互触碰”时,系统应该将这些改动标记为冲突状态,但合并操作本身永远成功。这让你可以在一个永不失败的系统之上,获得有意义的冲突呈现。

更智能的冲突标记

来看一个具体例子。两个人从同一个文件分支:

  • 甲删除了一个函数
  • 乙在这个函数中间添加了一行代码

传统 VCS 给你的是这样的冲突标记:

<<<<<<< left
=======
def calculate(x):
a = x * 2
logger.debug(f"a={a}")
b = a + 1
return b
>>>>>>> right

两块不透明的代码块。你需要脑补还原到底发生了什么。

Manyana 给你的是:

<<<<<<< begin deleted left
def calculate(x):
a = x * 2
======= begin added right
logger.debug(f"a={a}")
======= begin deleted left
b = a + 1
return b
>>>>>>> end conflict

每一部分都告诉你 发生了什么谁做的。左边删除了函数,右边在中间添加了一行。你可以看到冲突的结构,而不是盯着两块代码发呆。

CRDT 带来的深层改变

CRDT 提供了最终一致性:合并永不失败,而且无论以什么顺序合并分支——包括多个人独立工作的多个分支混在一起——结果始终相同。这个属性对版本控制设计的每个方面都有深远影响。

行顺序永久确定。当两个分支在同一点插入代码时,CRDT 选择一个顺序并固定下来。这解决了冲突部分被保留但在不同分支上以不同顺序解决的问题。

冲突是信息性的,不是阻塞性的。合并总是产生结果。当并发编辑发生在”太近”的地方时,冲突会被标记出来供审查,但它们从不阻塞合并本身。而且因为算法追踪的是 每一边做了什么,而不仅仅是展示两个结果,冲突呈现真正有用。

历史存在于结构中。状态是一个 weave——一个包含文件中曾经存在的每一行的单一结构,带有何时添加和删除的元数据。这意味着合并不需要寻找共同祖先或遍历 DAG。两个状态进去,一个状态出来,永远正确。

Rebase 不必销毁历史

Bram 特别兴奋的一个想法:rebase 不必销毁历史

传统的 rebase 创造一个虚构的历史,假装你的提交发生在最新的 main 之上。在 CRDT 系统中,你可以获得相同的效果——一次一个地在新基础上重放提交——同时保留完整历史。唯一需要的是在 DAG 中添加一个”主要祖先”注解。

这很重要,因为激进的 rebase 很快会产生没有单一共同祖先的合并拓扑,而这恰恰是传统三路合并崩溃的地方。CRDT 不在乎——历史在 weave 中,不是从 DAG 重建的。

项目现状

Manyana 目前是一个 demo,不是完整的版本控制系统。它大约 470 行 Python 代码,操作单个文件。Cherry-pick 和本地 undo 还没实现,但 README 中已经规划了如何优雅地实现它们。

但它证明了:基于 CRDT 的版本控制可以处理棘手的 UX 问题,并给出比我们今天使用的工具更好的答案——以及一个构建真正系统的连贯设计。

代码是公共领域的。完整的设计文档在 README 中。


个人思考

CRDT 在分布式系统领域已经相当成熟(被用于 Redis、Apple Notes、Figma 等产品),但在版本控制领域一直没有突破性的实践。Manyana 的价值在于它不仅讨论了技术可行性,还深入解决了”冲突呈现”这个真正影响开发者体验的问题。

如果这个方向能够发展成熟,我们可能会看到一个真正挑战 Git 的新一代版本控制系统。Git 的三路合并 + 基于文本的冲突标记确实是 2005 年设计的产物,是时候重新思考了。

关键要点

  • CRDT 让合并永不失败,冲突只是信息性标记
  • 新的冲突呈现方式让你看到”谁做了什么”,而不是两块代码
  • Rebase 可以保留完整历史,不需要销毁真相
  • 历史存在于 weave 结构中,合并不需要共同祖先
comments powered by Disqus