git - 重写 Git 历史记录时保持提交哈希的肮脏技巧?
问题描述
注意:有一个类似的问题How to keep commit hashs not change when using git filter-repo rewrite the history但答案集中在Git如何无法做到这一点。在这个问题中,我想探索理论上是否可以编写自定义脚本来保留提交哈希。
Gitfilter-branch
和BFG Repo-Cleaner是两个流行的工具,用于从回购历史中删除大文件和其他内容。它们导致不同的提交 SHA/哈希,这就是 Git 的工作方式,因为它“指纹”了提交的内容、其父级等。
但是,我们处于不幸的大文件提交发生在不久前的情况,并且我们有各种对较新提交的引用,例如在 GitHub 问题(“参见提交 f0ec467”)和其他外部系统中。如果我们使用 filter-branch 或 BFG,很多事情都会中断。
所以我来这里询问是否有一些肮脏的低级技巧,即使对于重写的提交,也可以保留提交 ID/SHA-1。我想,对于我们想要重写的错误提交,自定义脚本将创建一个新的 Git 对象,但“硬编码”相同/旧的 SHA-1,跳过它的计算。我认为较新的提交(它的孩子/后代)应该继续工作(?!)。
如果这不起作用,我想了解原因。Git 是否会定期检查哈希值是否与实际内容一致?它是否仅在某些操作期间这样做,例如gc
推或拉?
(我知道这是一个非常薄的冰,我只是在技术上探索我们的选择,然后我们接受我们将永远在我们的回购中拥有一个大型二进制文件,所有的影响,比如永远拥有更大的备份,完整的克隆需要更长的时间, ETC。)
更新:现在有一个公认的答案,但同时,没有答案提到git replace
这可能是解决方案?我做了一些基本的实验,但还不确定。
解决方案
我在评论中包含了一个链接,但实际上,破坏 SHA-1 并没有多大帮助。
问题在于 Gits 通过比较对象哈希 ID 来交换对象。这些目前是 SHA-1(有关未来的一些可能性,请参阅另一个问题及其答案)。如果您设法破坏 SHA-1,并生成一个生成相同哈希 ID 的新输入对象,您可以:
- 从 Git 的对象数据库中取出旧对象,然后
- 将新对象插入到 Git 的数据库中
从那时起,您的Git 将只看到新对象,而不是旧对象。但是当你将你的 Git 连接到另一个 Git 时,你的 Git 对另一个 Git 说:我有 object a123456...
,你想要吗?另一个 Git 可能只是回答:不,谢谢,我已经有了那个。 当然,他们有旧的。因此,您使您的 Git 与他们的 Git 不兼容,但没有从中获得任何收益。
如果另一个 Git没有相关对象,那么您就可以了!他们会要求您提供副本,您可以将其交出。
提交和标记对象在其中有一些空间来存储一些任意(不是完全任意)的用户数据。这是您放置扰动数据以破坏 SHA-1 的地方。树对象不太友好,但只要您可以使用提交和标记对象做您需要做的事情,您就可以绕过这个。
至于算力从哪里来,嗯,一大群树莓派电脑的价格要降下来了……
编辑:我忘了解决这个问题:
Git 是否会定期检查哈希值是否与实际内容一致?
是的。事实上,它每次通过哈希 ID 提取对象时都会执行此检查。请记住,大部分存储库是对象数据库,它是一个简单的键值存储。键是哈希 ID,存储在该键下的数据代表对象。Git 使用密钥进行查找,然后验证存储的数据哈希到该密钥,以确保存储的数据没有被磁盘或内存错误损坏。
推荐阅读
- javascript - 表单数组上的补丁值未设置材质多选的值
- javascript - 立即截断前导零
- unity3d - 如何在 Unity 中制作两个对象之间的交互动画?
- python - 由于 null,字符串连接不起作用
- r - 日期 %within% 间隔
- automapper - 在 Insert() 上未调用 Dapper Extensions 自定义 ClassMapper
- twitter-bootstrap - 如何使用我的样式自定义引导文档
- reactjs - 反应中的事件处理
- java - Java 和 Maven 不断从 ~/.profile 重置
- powershell - Powershell - 直接报告 - 递归