Git(Hub)如何处理来自短SHA可能的冲突?

67

Git和GitHub都显示SHA的短版本--仅显示前7个字符而不是全部40个字符--并且Git和GitHub都支持将这些短SHA作为参数。

例如:git show 962a9e8

例如:https://github.com/joyent/node/commit/962a9e8

考虑到可能性空间现在要低几个数量级,"只有" 2.68亿,Git和GitHub如何防止哈希碰撞?他们如何处理这些冲突?


1
在 GitHub 层面上,这不会是一个问题,因为 sha1 是每个项目独一无二的。 - Tone
22
在同一个项目中,两个仅包含7个字符的SHA1散列值发生碰撞的可能性仍然存在。 - Keith Thompson
有没有人知道是否可能使用GitHub的API获取短SHA的提交?例如,https://github.com/alexnaspo/var_dumpling-chrome/commit/9e9726ac 返回我需要的提交,但 https://api.github.com/repos/alexnaspo/var_dumpling-chrome/git/commits/9e9726ac 却没有。 - Alex Naspo
3个回答

69

这些缩写仅仅是为了简化视觉识别和让你的生活更加容易。实际上,Git并没有截断任何内容,在内部所有的值都将处理为完整值。你可以方便地使用部分SHA-1值,只要它足够清晰且至少四个字符长:

只要你提供了前几个字符,Git就足够聪明地找出你所需要的提交,只要你的部分SHA-1值至少有四个字符长度且清晰无误,也就是说,当前存储库中只有一个对象以该部分SHA-1值开头。


16
谢谢!这个链接进一步阐述了:“Git可以为您的SHA-1值计算出一个短而唯一的缩写。如果您在git log命令中传递'--abbrev-commit'参数,输出将使用更短的值,但保持它们的唯一性;它默认使用七个字符,但如果需要使SHA-1值无歧义,则会使它们变长。” - Aseem Kishore
14
另一个有用的语录:“通常,八到十个字符就足以在一个项目中保持唯一性。最大的Git项目之一——Linux内核,开始需要使用12个字符中的任意40个字符才能保持唯一性。” - Aseem Kishore
你的链接已经失效了... :( - Mrchief
@emboss 我认为问题不在于 Git 是否足够智能。假设您有一个 CI/CD,使用提交 SHA 的简短形式标记工件。在这种情况下,Git 的智能程度确实无关紧要。 - igops

35

我的存储库有一个提交记录,其ID为000182eacf99cde27d5916aa415921924b82972c

git show 00018

展示了修订版本,但是

git show 0001

打印

error: short SHA1 0001 is ambiguous.
error: short SHA1 0001 is ambiguous.
fatal: ambiguous argument '0001': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions

(如果您好奇,它是git本身的git存储库的克隆;该提交是Linus Torvalds在2005年做出的。)


9
如果您想知道哪些对象与您的模糊id(此案例中为“0001”)匹配,可以执行命令 git rev-list --all --objects | grep ^0001。获取可能的完整SHA1列表后,您可以对每个对象执行 git show 命令了解更多详细信息。 - Mikko Rantalainen
1
这个答案展示了如何仅使用git命令消除歧义。 - Jeremy

14

这里有两个要点:

  • 如果您在显示提交的 GitHub 页面的任何位置键入y,则会看到该提交的完整40字节。
    这说明了emboss的观点:GitHub不会截断任何内容。

  • 然而,自2010年以来,7个十六进制数字(28位)已经不够用了。
    请参见Linus Torwalds本人的提交dce9648(2010年10月,git 1.7.4.4):

最初的默认值为7是来自git开发早期,那时7个十六进制数字已经非常多了(它涵盖了大约2.5亿个哈希值)。当时我认为,65000个修订版本已经很多了(这是我们即将在BK中达到的数量),每个修订版本通常会有5-10个新对象左右,所以一百万个对象就是一个很大的数字。

(BK = BitKeeper)

如今,内核甚至不是最大的git项目,即使内核也有大约220k个修订版本(比BK树大得多),我们接近200万个对象。在这一点上,7个十六进制数字仍然对于其中很多对象是唯一的,但当我们谈论对象数量和哈希值之间只有两个数量级的差异时,截断哈希值就发生冲突。现在它已经远远不再是不现实的情况 - 它经常发生。

我们应该增加默认的缩写长度,因为原来的长度非常小,并且添加一种方式让人们在git配置文件中为每个项目设置自己的默认值。


我很好奇,什么是最大的git项目?或者至少,有哪些绝对庞大的git存储库是最好的例子? - GMA
1
@GeorgeMillo 正如http://blogs.atlassian.com/2014/05/handle-big-repositories-git/中所提到的,您有两种巨大的仓库(巨大的历史记录或巨大的二进制文件)。 Facebook是一个巨大的Git仓库示例:https://news.ycombinator.com/item?id=7648237(自那时起,他们已经转向了自己的Mercurial版本)。 - VonC
你的意思是7个十六进制数字(28位),而不是7位。 - Thomas Jacob
@ThomasJacob 谢谢您。我已相应地编辑了答案。 - VonC
@ThomasJacob 注意:SHA1 不会始终成为 Git 中使用的默认哈希算法。这是不断发展的:https://dev59.com/hF4c5IYBdhLWcg3wOoK6#47838703 - VonC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接