*通常*认为需要多少git sha才能唯一地标识给定代码库中的更改?

例如,如果您要构建一个目录结构,其中一个目录以Git存储库中的提交命名,并且希望它足够短以使您的眼睛不流血,但又足够长以使它发生碰撞的几率可以忽略不计,那么通常需要多少SHA子字符串呢?

假设我想唯一地标识这个更改:https://github.com/wycats/handlebars.js/commit/e62999f9ece7d9218b9768a908f8df9c11d7e920

我可以用最少的前四个字符: https://github.com/wycats/handlebars.js/commit/e629 < / p >

但我觉得那太冒险了。但是假设一个代码库在几年内可能有3万次更改,如果我使用8个字符,碰撞的几率是多少?12 ?对于这种事情,有没有一个通常被认为是可以接受的数字?

90828 次浏览

这个问题实际上在Pro Git书的第7章中得到了回答:

通常8到10个字符就足够唯一了 在一个项目中。最大的Git项目之一,Linux内核, 在40个角色中是否需要12个角色才能留下来 独一无二的。< / p >

对于短SHA, 7位数是Git的默认值,所以对于大多数项目来说都没问题。内核团队已经增加了几次,因为他们有几十万提交。因此,对于~30k次提交,8或10位数字应该完全没问题。

注意:你可以问git rev-parse --short最短但唯一的SHA1 参见“Git从常规哈希中获得短哈希”< / p >

git rev-parse --short=4 921103db8259eb9de72f42db8b939895f5651489
92110

在我的例子中可以看到,即使我指定的长度为4,SHA1的长度也为5。


对于大的回购,自2010年以来,7是不够的,提交dce9648由Linus Torvalds自己(git 1.7.4.4, 2010年10月):

默认值7来自git开发的早期,当时7个十六进制数字已经很多了(它涵盖了大约2.5亿+哈希值) 当时我认为65000次修订已经很多了(这是我们在《BK》中将要达到的目标),而且每次修订都倾向于大约5-10个新对象,所以100万个对象是一个很大的数字

(BK = BitKeeper)

现在,内核甚至不是最大的git项目,甚至内核也有大约22万个修订版本(比BK树还大),我们正在接近200万个对象 在这一点上,7个十六进制数字对于其中许多仍然是唯一的,但当我们谈论的对象数量和哈希大小之间只有两个数量级的差异时,截断哈希值中存在冲突 它甚至不再接近于不现实——它一直在发生

我们都应该增加默认的缩写,增加了一种方法,让人们可以在git配置文件中设置他们自己的每个项目的默认值

core.abbrev

设置长度对象名称缩写为。
如果未指定,许多命令缩写为7个十六进制数字,这可能不足以使缩写的对象名称在足够长的时间内保持唯一

environment.c:

int minimum_abbrev = 4, default_abbrev = 7;

注意:正如下面的评论 by marco.m一样,core.abbrevLength在同一Git 1.7.4.4中的提交a71f09f中被重命名为core.abbrev

core.abbrevlength重命名为core.abbrev

毕竟它对应于--abbrev=$n命令行选项。


最近,Linus在提交e6c587c (for Git 2.11, Q4 2016)中添加了:
(如在Moy马修回答中提到的)

在相当早期的时候,我们决定将对象名称缩写为7位十六进制数字,但随着项目的发展,越来越有可能看到早期制作的如此短的对象名称,并且记录在日志消息中不再是唯一的。

目前Linux内核项目需要11到12位十六进制数字,而Git本身需要10位十六进制数字来唯一地标识它们所拥有的对象,而许多较小的项目可能仍然可以接受最初的7位十六进制默认值。一种方法并不适用于所有项目。

引入一种机制,在第一次请求时,我们估计存储库中的对象数量,用默认设置缩写对象名称,并为存储库提供一个合理的默认值。当使用对象名称缩短到前N位时,我们期望在存储库中与2^(2N)对象发生冲突,因此使用足够数量的十六进制数字来覆盖存储库中的对象数量 我们在缩短的名称中添加的每个十六进制数字(4位)允许我们在存储库中拥有4倍(2位)的对象

参见提交e6c587c (01 Oct 2016) by Linus Torvalds (torvalds) 参见提交7 b5b772提交65年acfea (01 Oct 2016) by juno C Hamano (gitster).
(由Junio C Hamano—gitster in 提交bb188d0合并,03 Oct 2016)

这个新属性(猜测一个合理的SHA1缩写值的默认值)直接影响Git为发布计算自己的版本号

这个问题已经被回答了,但是对于那些寻找背后数学的人来说——它被称为生日问题 (维基百科)。

它是关于一组N人中有2人(或更多)在一年中同一天过生日的概率。这类似于2个(或更多)git从存储库提交,总共有N个具有相同长度为X的哈希前缀的提交。

看看概率表。例如,对于长度为8的哈希十六进制字符串,当存储库只有大约9300个条目(git提交)时,发生冲突的概率达到1%。对于11万次提交,概率是75%。但是如果你有一个长度为12的哈希十六进制字符串,那么在10万次提交中发生碰撞的概率低于0.1%。

Git 2.11版(也许是2.12版?)将包含一个特性,可以根据项目的大小来调整短标识符(例如git log --oneline)中使用的字符数。一旦你使用了这样的Git版本,你的问题的答案可以是“选择Git给你的git log --oneline的任何长度,这是足够安全的”。

有关更多细节,请参见更改“core.abbrev”的默认值?Git Rev News第20版中的讨论并提交bb188d00f7

这就是所谓的生日问题。

对于小于1/2的概率,碰撞的概率可以近似为

p ~= (n2)/(2m)

其中n是项目的数量,m是每个项目的可能性的数量。

十六进制字符串的可能性数是16c,其中c是字符数。

对于8个字符和30K提交

30k ~= 2__abc0

p ~ = (n2) /(2米)~ = ((2 __abc1) 2) / (2 * 16 __abc3) = 2 __abc4/2__abc5 =⅛

增加到12个字符

p ~ = (n2) /(2米)~ = ((2 __abc1) 2) / (2 * 16 __abc3) = 2 __abc4/2__abc5 = 2 __abc6