重写 Git 历史记录时保留提交哈希值的肮脏技巧?

Bor*_*ard 8 git

注意:有一个类似的问题How to keep commit hashs not change when use git filter-repo rewrite the History,但答案集中在Git如何不能做到这一点上。在这个问题中,我想探讨理论上是否可以编写自定义脚本来保留提交哈希值。

Gitfilter-branchBFG Repo-Cleaner是两种流行的工具,用于从存储库历史记录中删除大文件和其他内容。它们导致不同的提交 SHA/散列,这就是 Git 的工作方式,因为它“指纹”提交的内容、其父项等。

然而,我们面临的情况是,不久前发生了不幸的大文件提交,并且我们有各种对较新提交的引用,例如在 GitHub 问题(“参见提交 f0ec467”)和其他外部系统中。如果我们使用过滤器分支或 BFG,很多东西都会被破坏。

所以我来这里询问是否有一些肮脏的、低级的技巧如何保留提交 ID / SHA-1,即使是重写提交。我想,对于我们想要重写的错误提交,自定义脚本将创建一个新的 Git 对象,但“硬编码”相同/旧的 SHA-1,跳过它的计算。我认为较新的提交(其子级/后代)应该继续工作(?!)。

如果这行不通,我想了解为什么。Git 是否定期检查哈希值是否与实际内容一致?它是否仅在某些操作(例如gc推或拉)期间执行此操作?

(我知道这是一个非常薄冰的情况,在我们接受我们将永远在我们的仓库中拥有一个大型二进制文件之前,我只是在技术上探索我们的选择,其所有影响包括永远拥有更大的备份,完整克隆需要更长的时间, ETC。)


更新:现在有一个被接受的答案,但与此同时,没有答案提到git replace这可能是解决方案?我已经做了一些基本实验,但还不确定。

tor*_*rek 7

我添加了一个链接作为评论,但事实上,破坏 SHA-1 并没有多大帮助。

问题是 Git 通过比较对象哈希 ID 来交换对象。这些目前是 SHA-1(有关未来的一些可能性,请参阅其他问题及其答案)。如果您设法破解 SHA-1,并生成一个新的输入对象来生成相同的哈希 ID,您可以:

  • 从 Git 的对象数据库中删除旧对象,然后
  • 将新对象插入到 Git 的数据库中

从那时起,你的Git 将只能看到新对象,而不是旧对象。但是当你将你的 Git 连接到其他 Git 时,你的 Git 对另一个 Git 说:我有对象a123456...,你想要它吗?另一个 Git 可能会回答:不用了,谢谢,我已经有了那个。当然, 他们有旧的。所以你已经让你的 Git 与他们的 Git 不兼容,但是却没有从中得到任何好处。

如果其他 Git没有相关对象,那么就没问题了!他们会要求您提供副本,您可以将其交给您。

提交和标记对象中有空间容纳任意(不是完全任意)的用户数据。您可以在此处放置用于破坏 SHA-1 的扰动数据。树对象不太友好,但是只要您可以使用提交和标记对象执行您需要的操作,您就可以绕过这个问题。

至于从哪里获得计算能力,嗯,一大群 Raspberry Pi 计算机的价格正在下降......

编辑:我忘了回答这个问题:

Git 是否定期检查哈希值是否与实际内容一致?

是的。事实上,每次通过哈希 ID 提取对象时,它都会执行此检查。请记住,大多数存储库的大部分是对象数据库,它是一个简单的键值存储。键是哈希 ID,存储在该键下的数据代表该对象。Git 使用该密钥进行查找,然后验证存储的数据是否散列到该密钥,以确保存储的数据没有因磁盘或内存错误而损坏。