摘要

名称写进了对象内部

Git 的对象名由对象内容计算而来。一个普通文件的 blob 可以保留原字节,再用新算法算出新名字。树对象却包含它所指向的文件和子树的名字;提交对象又包含树及父提交的名字。标签也可能指向其他对象。迁移设计把这条链写得很清楚:替换被引用对象的名称,会改变引用者的内容;引用者随后又需要一个新名称。沿着提交历史往回走,账本不是一张可批量换皮的贴纸。

这解释了为什么“把 SHA-1 改成 SHA-256”看似一行配置,实际却涉及整张对象图。旧对象名留在已有仓库、远端服务、工具和人们保存的引用里。新对象名对应同一份文件内容时,需要有人记录两套名字之间的关系。哈希函数只负责计算名字,不会自动给旧世界开一张迁移证。

2018 年方案于是提出双向名称映射:让仓库逐个转向 SHA-256,同时争取与 SHA-1 服务器通信。文档列出阶段和边界,初期设计并未把新协议支持纳入其中。这份方案最有价值之处,是没有把选定算法冒充成已经修好的桥梁。它承认了过渡期间两套地址都必须有人照管。

命令行选项先到了

Git 2.29.0 的 git-init 手册在 2020 年给出 --object-format=sha256。旁边的警告并不含糊:这是实验性功能,主要用于测试,通常无法与 SHA-1 仓库共享工作。创建一个采用新格式的本地仓库,与把它接入现有协作网络,是两个不同的验收项目。

再看Git 2.54.0 手册:2026 年,sha1 仍是默认对象格式,sha256 可供选择,而两种格式的仓库“目前没有互通性”。这不是说六年间什么也没做;它说明最难的那一项不能从选项存在推导出来。软件往往先允许少数人造新船,再慢慢解决港口能否接船。

Git 的重大变更计划希望在 Git 3.0 让 SHA-256 成为新建仓库的默认格式。文件没有给出发布日期,还把依赖库、应用和托管服务的准备情况列为前提;项目也尚未计划废弃 SHA-1 对象格式。因此,未来可能同时存在大量旧格式仓库与新格式仓库。默认值的变化能改变新增量,无法改写已经存储和依赖旧名的历史。

谁来支付互通账单

2018 年方案讨论了 SHA-1 的弱点及 2017 年 SHAttered 碰撞,并选择 SHA-256。安全动机明确,迁移成本也明确:树、提交和标签的字节因名称变化而变化;外部软件必须识别和处理新格式;跨格式工作还要可靠地匹配对象。维护者可以宣布目的地,却不能替每个库、每家托管服务和每份旧仓库完成旅程。

这段历史的讽刺不在于“选错了算法”,而在于我们太爱把命名问题写成行政动作。Git 的名字同时是内容的索引和内容的一部分。工程提案有自己的时间表,已经运行的网络有另一张。后者一直在收取过桥费。