计算机科学家 David Chisnall 用 Vim 超过 20 年,写过 5 本书、1 篇博士论文和 150 多篇文章。对他来说,肌肉记忆里最值钱的安全网是持久化撤销:上周删掉的段落、重启系统前的草稿,随时能跨越数月回溯找回。

然而,当他初次尝试作为现代化分支的 Neovim 时,这一沿用 20 年的底层安全网被直接打碎。Neovim 不仅无法读取旧的撤销历史,还将 Vim 原有的持久化撤销文件覆写为 Vim 无法解析的格式,导致两边的历史记录彻底失效。更令他退坑的是社区反馈时的冷淡回应:持久化撤销格式并不稳定,用户“不该依赖名为 persistent 的功能来保存数据”。

这件事很快在开发者社群蔓延开来。表面上是一起兼容性故障,底层却牵扯出基础软件开发中极具破坏性的认知裂痕:当激进重构遭遇传统生产力,开源工具到底对用户负有怎样的注意义务?

版本跃迁背后的格式断裂

很多人误以为这只是一次粗糙的代码删除,但深入技术细节会发现,这是一场由现代架构演化引发的工程事故。

Vim 与 Neovim 的持久化撤销机制,本质上是把缓冲区的撤销树和文件哈希序列化写入磁盘。在 Vim 体系中,写入文件的协议版本常年停留在 version 2。而 Neovim 推进到 0.5 版本时,为了深度集成 Tree-sitter 语法树解析与异步插件生态,合并了 PR #13973,强制将 extmark 字节级编辑信息存入撤销文件。

这一改动直接将 Neovim 内部的撤销文件规范推升至 UF_VERSION 3。

Neovim 0.5 撤销文件格式断裂链路 Vim 传统规范 存储格式版本: UF_VERSION 2 依赖行级与基础字符流 20年跨大版本兼容 状态:稳定长期基线 PR #13973 变更 存储格式升级: UF_VERSION 3 强制加入 extmark 适配 Tree-sitter 语法树 破坏旧版文件兼容 终端冲突后果 魔数共享但协议冲突: 共享目录同名覆盖 Vim 拒绝读取 V3 格式 Neovim 忽略旧文件 历史数据静默蒸发

两者在底层共用了相同的文件魔数,协议却不再互通。官方文档注明 Neovim 不会自动主动删除 undo 文件,但当用户在共享目录下用 Neovim 写入新格式时,同名文件被覆写;加之文件内容只要发生哈希不匹配就会被软件直接忽略,旧版 Vim 打开后面对 version 3 格式更是直接拒绝加载。对终端创作者来说,现象极其冰冷:积攒多年的撤销链条,在一瞬间全部打不开。

官方 breaking changes 追踪 issue #14090 明确记载,新版本无法读取 PR #13973 之前的撤销文件。官方给出的恢复路径,竟是让用户自行寻找并编译 Neovim 0.4 或 commit bda1292 之前的旧版本,以此导出旧数据。

社区曾有人提交 PR #14978,试图实现一套撤销文件格式迁移转换工具,但在权衡维护成本后,该 PR 最终被关闭。技术演进向前奔跑,旧历史的处理被直接留在原地。

内部缓存还是数字资产

这场冲突的本质,是工具开发者与终端使用者之间心智模型的剧烈错位。

软件一旦将数据持久化到文件系统,就承担了保全该数据的信义义务。

在 Neovim 核心开发者的认知里,撤销文件是一份高度依赖编辑器内部 AST 语法树和缓冲区字节的高级内部缓存。为了给现代化插件生态让路,内部缓存可以推倒重来;拒绝读取校验不符的文件,是为了防止用户误回滚导致当前文件坏损。

但在严肃作者眼中,带有“持久化”标识的文件绝不是阅后即焚的缓存。它是写作者的撤回权、容错率和安全垫,是一项受法律与伦理保护的数字资产。

心智模型错位:两种对立的工程视角 系统极客:内部状态缓存 定位:服务于 AST 语法树的高级临时缓存 机制:字节变动或哈希不符即丢弃 优先级:架构解耦与插件生态高于兼容 诉求:用户应自行配置 Git 等外部备份 结论:格式可按需 breaking change 创作者:底层数字资产 定位:跨越系统重启的最后安全保护网 机制:信赖命名为 persistent 的功能承诺 优先级:数据完整性是软件不可逾越的底线 诉求:不得在无隔离提示下覆盖数据 结论:静默失效即破坏注意义务

人机界面先驱 Jef Raskin 在 2000 年的著作《人机界面》(The Humane Interface)中提出了著名的拉斯金定律,第一条便是:计算机不得损害用户的工作,亦不得因不作为而致使用户的工作受到损害。

Neovim 在工程上为了引入 Tree-sitter 没有错,错在技术治理的傲慢与粗糙。如果需要推翻格式,完全可以更换文件扩展名、使用独立的目录命名空间,或者保留迁移工具做版本过渡。直接复用同名机制、覆盖磁盘存储,并在事后告知用户“不该信任该功能”,直接击穿了软件最基础的注意义务。


生产力工具的防线

眼下,撤销文件的死锁仍未彻底解决。Neovim 仓库中 issue #25690 仍在反复讨论是否要引入 :rundo! 这种强制读取指令,以挽救源文件发生外部变动后被编辑器主动拒认的历史树。这表明由严格哈希校验导致的撤销链条失效,至今仍困扰着生产环境中的重度用户。

官方安全指引随后做出了修正:明确要求 Vim 与 Neovim 必须配置各自独立的撤销目录,并强调持久化撤销仅应作为便捷恢复手段,而非可靠的长期归档。

  • 建议.混用两款编辑器的写作者,必须在配置文件中严格隔离 undodir 路径,避免底层格式覆写造成灾难。

技术的革新往往伴随代价,但代价不该由用户的心血来单向买单。老派 Unix 工具之所以能跨越数十年依然受人尊崇,正是因为它们在极其克制地守护着数据的连续性;而激进的重构一旦轻视了对用户资产的敬畏,走得再快,也会失去立身之本。