替换损坏的 GIT blob

Replacing corrupt GIT blob

我有一个本地 GIT 存储库(没有远程备份,我吸取了教训)并且有损坏。我在一次提交中将其追踪到一个 blob(文件)。内容来自另一个文件并且被截断了。损坏的 blob 在两次提交中。然后是更新版本的文件。

你能建议一下如何解决这个问题吗?我有一些想法,但我对 GIT 的经验有限。

  1. 使用 git hash-object 制造一个正确的 blob。但随后它将具有不同的哈希值。我可以重命名文件吗?

  2. 将两个受影响的提交中的损坏 blob 替换为 git replace。这样做有什么潜在的危险吗?

  3. 历史上大约有 15 次损坏。我可以重置为损坏前的提交并手动重做更改。也许我可以重新设置以后的提交。

Git 处理检测到的损坏对象的设施是......充其量是原始的。通常的方法是进行一些备份,但在这种情况下,该选项似乎已失效。 (但请考虑本地备份,例如,如果有 Time Machine。)

如果损坏的对象(在本例中为 blob)是一个 松散 对象,并且您知道正确的 内容,您可以删除错误的松散目标文件并使用 git hash-object -w 创建正确的松散目标文件,它巧妙地修复了所有问题。但是,大概您不知道正确的内容,这就是导致您这样做的原因:

  1. Fabricate a correct blob using git hash-object. But then it will have a different hash.

也就是说,您编写了一些内容——大概是全新的——并使用 git hash-object -wgit hash-object -w -t blob-t blob 是默认值)将其写入对象存储。就目前而言,这一切都很好,但它不会 replace bad 对象。

Can I just rename the file?

不,那无济于事:提交包含一个 tree 对象或一系列树对象,它们提供名称,然后通过 blob 哈希引用文件的内容ID。这些树将继续存在。他们通过哈希 ID 引用损坏的 blob 对象:他们说,例如,“在提取此提交时,文件 path/to/file 是模式 100644 (rw-r--r--) 并且来自 blob ”。像所有 Git 对象一样,一旦写入,它们可能不会被更改——覆盖它们的数据只会产生一个损坏的对象,即其数据散列与告诉 Git 的散列名称不匹配的对象检索数据。

因此您需要补充 tree 对象。这些反过来需要替换提交对象,这需要替换所有“下游”提交(具有此提交作为任何祖先的提交)。此时你最好使用 git filter-repo 或等价物。 (使这项工作成为从损坏的存储库中恢复的 一般 方法将大大有助于修复我从这里开始的“最好的原始”,并且从长远来看,这可能是要走的路。)

  1. Replace the corrupt blob in the two affected commits by git replace.

这实际上可能工作得很好,之后,您可以 运行 git filter-repo 或旧的 git filter-branch 将存储库重新复制到缺少对损坏的引用的存储库blob object.1 至少在概念上(您根本不需要使用 git replace-object)将其与 filter-repo 的某种修复选项相结合,我们在适当的维修设施方面取得进展。

Is there any potential danger with that?

它将损坏的 blob 留在 存储库中。这可能会对以后重新打包的尝试产生一些影响,所以我绝对想使用 git filter-* 技巧。

  1. The corruption is about 15 commits deep in history. I could reset to the commit before the corruption and manually redo the changes. Perhaps I could then rebase the later commits.

这本质上是 git filter-* 方法在 git replace 之后的手动版本。

使用 git filter-repo 在某种意义上更安全,因为 filter-repo 使用 git fast-exportgit fast-import “在幕后”构建一个全新的存储库从原始输入。这意味着新建的存储库(快速导入的结果)从一开始就没有引入任何损坏的对象。这里真正的问题是 git fast-export 是否可以 有损坏的 blob 的存储库上工作,也许在使用 git replace 或其他一些技巧之后。


1注意:我在这里说“可以”就好像这只是 运行 命令的问题。 可能确实如此!但它 可能 git fast-export 操作中途死亡,偶然发现了损坏的对象。所以这可能会变成 Small Matter of Programming。在 理论 中它应该是可行的,因为我们不需要或不需要出于任何目的的坏对象。