Git哈希重复

时间:2019-05-06 20:48:34

标签: git hash probability

Git允许使用以下命令来检索提交的哈希值:

git rev-parse HEAD

给出33b316c

git rev-parse --short HEAD

给出33b316cbeeab3d69e79b9fb659414af4e7829a32 我知道实践中的长哈希值永远不会冲突。

在实践中,短哈希的使用频率更高。我想知道矮个子碰撞的可能性是多少? git是否采取任何措施来克服可能的冲突(例如,使用git checkout)?

2 个答案:

答案 0 :(得分:4)

我在book中给出了一个公式(请参阅第78-79页),但是如果您要查找一个简单的公式,则为 some 哈希碰撞的概率当您对大约2 n / 2 个键进行哈希处理时,在n位哈希中达到大约50%。 SHA-1哈希本身是160位,表示为40个十六进制数字,每个代表160位中的4位。截断为7个十六进制数字会留下28位,因此您将在大约2 14 键或16384个对象上达到50%的碰撞机会。如果将对象限制为仅提交,则提交的数量相当可观,但是Git将所有对象(提交,树,带注释的标记对象和Blob)放置在单个哈希索引键值存储中。

任何给定键对散列冲突的概率仅为2 n 中的1,即2 28 中为1或2.68亿中的1。随着密钥数量的增加,它之所以迅速增加到50%的原因,被称为生日悖论或birthday problem。 50%当然太吓人了;使用28位,如果我们希望总体概率低于0.1%,则应将对象数保持在1230以下。通过使用32位(8个字符缩写),我们将其加倍到大约2460,但这仍然不是很多对象。

当您的商店中有16k个对象时,您可能应该至少使用10个十六进制数字,给出2 40 个可能的哈希值和约0.999987794的p-bar值... (约有0.019%的碰撞机会)。九个十六进制数字仅提供2 36 哈希值,产生的p条为.99804890 ...或碰撞的机会为0.19%,我认为这太高了。

如果您可以将模糊匹配的代码限制为仅提交-或仅 commit-ish ,这在Git中表示 commit或带注释的标签-内置的默认工作方式很不错。 (实际上,在很多情况下,Git都会这样做。)但是,至少在我看来,Git用于计算“正确的”缩写长度的内部代码太过粗心,"loosey-goosey"也是如此,因为它使用了在产生的哈希值可用于识别任何对象的情况下,冲突概率为50%的平方根技巧。

(如注释中所述,内部 Git始终使用完整的哈希。它仅在非Git / Git界面上使用,例如git log <hash>git show <hash>用户-面对命令,您可以键入一个缩写的哈希值,或要求一个缩写的输出哈希值。在这里,Git默认使用50%-collision-probability数字来计算要显示的字符数,从估计的字符数开始数据库中的对象。如果要提供哈希,则选择要提供的哈希值。如果要Git提供哈希,则仍可以使用--abbrev=number选择数量请注意,绝对最小值为4:git log abc不会将abc视为哈希ID,但是git log abcd会将abcd视为哈希ID的缩写。也是从1.7版本的Git开始的非常旧的默认7个字符。)

答案 1 :(得分:2)

回购的短哈希列表中重复的机会随着提交次数的增加而迅速增加。

但是,它不会引起太多问题,因为这些问题根本不是唯一的,它们只是一种舒适功能,提供了在某些命令中指定提交的另一种方法。

当您选择给命令填充一个简短的哈希,而该哈希实际上在您的仓库中 是不明确的(即无法解析为唯一的提交)时,git会提示您一个候选列表,并您可以选择要拨打的电话。

示例输出:

$ git ch 2334
error: short SHA1 2334 is ambiguous
hint: The candidates are:
hint:   233475fec8 commit 2018-02-14 - Merge pull request #175 in someRepo from someBranch to someOtherBranch
hint:   2334790f05 commit 2018-06-14 - Merge pull request #917 in someRepo from someBranch to yetAnotherBranch
hint:   233415cfa2 tree
hint:   233438d772 tree
hint:   23348a014a tree
error: pathspec '2334' did not match any file(s) known to git

例如,这是用于在CLI中键入的git checkout <shortHash>,但是我不确定它在脚本上下文中的行为。要么它退出代码为1时出错,要么它自动采用其中一个候选者,我必须检查一下。