Git SHA-256 默认变更:一场技术决策的反思
Git SHA-256 默认变更揭示了技术决策背后的商业账和效率主义代价。
Git SHA-256 默认变更:一场技术决策的反思
Git 3.0 把 SHA-256 做默认哈希,这事儿听着像「安全升级」,其实是一场把全球开发者时间当免费燃料烧的表演。
Scott Chacon 算过一笔账:全球约 4000 万活跃 Git 仓库,按平均 5000 次提交估算,仅重新计算对象哈希就要消耗 2000 亿次 SHA-256 运算。换算成 AWS Graviton3 实例,单次迁移成本约 1.2 亿美元电费,不算人力。而这笔账单,最终由每个在 CI/CD 里跑 git fetch 的工程师买单。
Git 用 SHA-1 做内容寻址,从来不是为了「防碰撞攻击」。Git 的威胁模型是:同一个 blob 在全球任何仓库里哈希值都一样,便于去重和同步。SHA-1 的首原像抗性至今未破,次原像抗性也没人能实战利用。2017 年 SHAttered 造出的碰撞 PDF,需要 2^63 次运算,且前缀固定——你根本塞不进 Git 对象数据库,因为 Git 会在内容前加 blob 123\0 这种前缀,破坏了碰撞构造的前提条件。Linus 2017 年就说过:"Git doesn't really rely on SHA-1 for security"(Git 并不真正依赖 SHA-1 做安全)。可这句大实话,在 NIST「弃用 SHA-1」的文件面前,没人爱听。
反方会说:NIST 都发文弃用 SHA-1 了,浏览器都撤信任了,Git 不跟进算「技术债」。这话乍听有理,细想是混淆威胁模型。TLS 证书要防中间人伪造,需要抗碰撞;Git 要防的是「同一个提交在不同机器上哈希不一致」,这只需要首原像抗性。SHA-1 的首原像抗性至今 2^160,量子计算机也得 Grover 算法跑 2^80 步——比 SHA-256 的 2^128 也就弱一点点,但在「地球上所有原子算到热寂」这个量级面前,区别纯属数学洁癖。真要较真,Git 早该把对象头部的 blob/tree/commit 类型前缀去了,那才是真正的协议债。
这事儿跟 IPv6 迁移像极了——区别在于 IPv6 解决地址枯竭是真痛点,而 SHA-256 解决的是「合规清单上有个勾没打上」。我见过某大厂基础设施组,为了「合规」把内网 2000 个微服务仓库强制 git filter-repo 换哈希,跑了三周集群,搞挂了两次发布窗口,最后发现下游依赖的 go.mod 里全是旧哈希引用,回滚又花了一周。这哪是安全升级,分明是把「合规成本」外部化给下游。GitHub 早就支持 SHA-256 仓库,但默认不开,因为他们知道:一旦开成默认,全网 Action 缓存失效、Dependabot 报错、Git LFS 指针断裂,客服工单量会涨十倍。这账,微软算得比谁都清。
有家做嵌入式的公司,CI 跑在自建 Jenkins 上,节点还是 2018 年的 Xeon E5。Git 3.0 一出,他们的 git clone --depth=1 突然慢了 40%,因为 SHA-256 没有硬件加速指令,老 CPU 跑软实现吃满单核。基础设施组没预算换机器,只能把并发任务数从 20 降到 12,发布周期从一天拉长到两天。老板问为什么,架构师说:「上游换了哈希算法。」老板骂了一句脏话,批了采购单。这笔钱,算不进 Git 核心团队的 KPI 里。
技术决策的商业账,永远藏在「谁受益、谁买单」的错位里。Git 核心团队由 Google、GitHub、GitLab 工程师主导,他们有最好的 CI 集群、最新的 CPU、最完善的迁移工具。对他们来说,SHA-256 只是改个默认配置、跑过测试套件的事。但对地下室里维护十年老项目的自由开发者,对还在用 CentOS 7 跑 Jenkins 的外包团队,这不是默认变更——是强制破坏性更新。效率主义最残酷的地方,不是追求效率,是用「整体最优」的名义,把边际成本全推给了没有话语权的长尾。
说白了,Git 3.0 这波操作,本质上是标准制定权对安装基数的收割。就像当年的 Python 3 强制 Unicode、Java 9 模块化、React 18 并发模式——每次大版本破坏性变更,都是生态头部把迁移成本平摊到长尾的一次合法化收税。区别在于 Python 3 解决了真痛点(中文乱码),Java 9 解决了真痛点(JAR 地狱),而 SHA-256 默认化,解决的是「合规文档里不能写 SHA-1」这个伪痛点。
下次当某个 RFC 把「SHOULD」改成「MUST」,某个基础设施把「实验特性」改成「默认开启」时,别光看技术参数。先问一句:这笔迁移账单,寄给谁了?