我做了一个实验来确切了解 Git 在这种情况下的行为方式。这是版本 2.7.9~rc0+next.20151210(Debian 版本)。我基本上只是通过应用以下差异并重建 git 将哈希大小从 160 位减少到 4 位:
--- git-2.7.0~rc0+next.20151210.orig/block-sha1/sha1.c
+++ git-2.7.0~rc0+next.20151210/block-sha1/sha1.c
@@ -246,6 +246,8 @@ void blk_SHA1_Final(unsigned char hashou
blk_SHA1_Update(ctx, padlen, 8);
/* Output hash */
- for (i = 0; i < 5; i++)
- put_be32(hashout + i * 4, ctx->H[i]);
+ for (i = 0; i < 1; i++)
+ put_be32(hashout + i * 4, (ctx->H[i] & 0xf000000));
+ for (i = 1; i < 5; i++)
+ put_be32(hashout + i * 4, 0);
}
然后我做了一些提交并注意到以下内容。
- 如果已存在具有相同哈希的 blob,则根本不会收到任何警告。一切似乎都正常,但是当您推送、有人克隆或您还原时,您将丢失最新版本(符合上述说明)。
- 如果树对象已经存在并且您使用相同的哈希创建了一个 blob:一切看起来都很正常,直到您尝试推送或有人克隆您的存储库。然后你会看到这个 repo 已经损坏了。
- 如果提交对象已经存在并且您使用相同的哈希创建了一个 blob:与 #2 相同 - 损坏
- 如果 blob 已经存在并且您使用相同的哈希创建提交对象,则更新“ref”时它将失败。
- 如果 blob 已经存在,并且您使用相同的哈希创建树对象。创建提交时会失败。
- 如果树对象已经存在并且您使用相同的哈希创建提交对象,则更新“ref”时它将失败。
- 如果一个树对象已经存在并且你创建了一个具有相同散列的树对象,那么一切看起来都没有问题。但是当您提交时,所有存储库都会引用错误的树。
- 如果一个提交对象已经存在,并且您使用相同的哈希创建一个提交对象,那么一切看起来都正常。但是当您提交时,将永远不会创建提交,并且 HEAD 指针将移动到旧提交。
- 如果一个提交对象已经存在并且你用相同的哈希创建一个树对象,创建提交时它会失败。
对于#2,当你运行“git push”时,你通常会得到这样的错误:
error: object 0400000000000000000000000000000000000000 is a tree, not a blob
fatal: bad blob object
error: failed to push some refs to origin
或:
error: unable to read sha1 file of file.txt (0400000000000000000000000000000000000000)
如果你删除文件然后运行“git checkout file.txt”。
对于 #4 和 #6,您通常会收到如下错误:
error: Trying to write non-commit object
f000000000000000000000000000000000000000 to branch refs/heads/master
fatal: cannot update HEAD ref
运行“git commit”时。在这种情况下,您通常只需再次输入“git commit”,因为这将创建一个新的哈希(因为更改了时间戳)
对于 #5 和 #9,您通常会收到如下错误:
fatal: 1000000000000000000000000000000000000000 is not a valid 'tree' object
运行“git commit”时
如果有人试图克隆您损坏的存储库,他们通常会看到如下内容:
git clone (one repo with collided blob,
d000000000000000000000000000000000000000 is commit,
f000000000000000000000000000000000000000 is tree)
Cloning into 'clonedversion'...
done.
error: unable to read sha1 file of s (d000000000000000000000000000000000000000)
error: unable to read sha1 file of tullebukk
(f000000000000000000000000000000000000000)
fatal: unable to checkout working tree
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry the checkout with 'git checkout -f HEAD'
让我“担心”的是,在两种情况下 (2,3),存储库在没有任何警告的情况下损坏,在 3 种情况下 (1,7,8),一切似乎都正常,但存储库内容与实际情况不同你期望它是。克隆或拉取的人将拥有与您拥有的内容不同的内容。案例 4、5、6 和 9 都可以,因为它会因错误而停止。我想如果它至少在所有情况下都因错误而失败会更好。