比如说,如果你要构建一个目录结构,其中一个目录是为Git仓库中的一个提交命名的,你希望它足够短,不会让你的眼睛流血,但又足够长,冲突的可能性可以忽略不计,那么通常需要多少SHA子串?
假设我想唯一标识此更改:https://github.com/wycats/handlebars.js/commit/e62999f9ece7d9218b9768a908f8df9c11d7e920
我可以使用最少的前四个字符:https://github.com/wycats/handlebars.js/commit/e629
但我觉得这样做会有风险。但假设一个代码库在几年内可能会有比如说30k的变化,如果我使用8个字符,冲突的可能性有多大?12个?对于这类事情,有没有一个通常被认为是可以接受的数字?
5条答案
按热度按时间lstz6jyr1#
注意:您可以要求
git rev-parse --short
提供最短且唯一的SHA1。参见"git get short hash from regular hash"
正如您在我的示例中看到的,即使我指定了长度4,SHA1的长度也是5。
自2010年以来,对于大型回购来说,7次回购是不够的,Linus Torvalds自己也提出了commit dce9648(git www.example.com,2010年10月):1.7.4.4, Oct 2010):
默认值7来自于git开发的早期阶段,当时7个十六进制数字是很多的(它覆盖了大约2.5亿个哈希值)。
当时我认为65k的修订是一个很大的数字(这是我们即将在BK中遇到的),每个修订往往是大约5 - 10个新对象左右,所以一百万个对象是一个很大的数字。
(BK=比特守护者)
如今,内核甚至不是最大的git项目,甚至内核也有大约22万个修订版本(比BK树大得多),我们正在接近200万个对象。
在这一点上,7个十六进制数字对许多人来说仍然是唯一的,但当我们讨论对象数量和哈希大小之间只有两个数量级的差异时,截断的哈希值 * 将 * 发生冲突。
这已经不再是不切实际的事情了--它一直在发生。
设置对象名称缩写为的长度。
如果未指定,许多命令会缩写为7个十六进制数字,这可能不足以使缩写的对象名称在足够长的时间内保持唯一。
environment.c
:注意:如marco.m所述,在commit a71f09f中的同一Git www.example.com中,
core.abbrevLength
在core.abbrev
中被重命名1.7.4.4 in commit a71f09f将
core.abbrevlength
重命名为core.abbrev
它毕竟对应于
--abbrev=$n
命令行选项。最近,Linus在commit e6c587c中添加了以下内容(Git 2.11版,2016年第4季度):
(as在Matthieu Moy的answer中提到)
在相当早期的日子里,我们不知何故决定将对象名称缩写为7个十六进制数字,但随着项目的增长,越来越有可能看到早期创建的如此短的对象名称,并记录在日志消息中,不再是唯一的。
目前Linux内核项目需要11到12个十六进制位,而Git本身需要10个十六进制位来唯一标识它们所拥有的对象,而许多较小的项目可能仍然可以使用最初的7个十六进制位默认值。
引入一种机制,我们可以在第一次请求使用默认设置缩写对象名称时估计存储库中的对象数量,并为存储库提供一个合理的默认值。当使用缩写为前N位的对象名称时,我们会看到存储库中的
2^(2N)
对象发生冲突,基于这种预期,使用足够数量的十六进制数字来覆盖存储库中的对象数量。我们添加到缩写名称的每个十六位数(4位)允许我们在存储库中拥有四倍(2位)的对象。
参见Linus Torvalds (
torvalds
)的commit e6c587c(2016年10月1日)。参见commit 7b5b772、commit 65acfea(2016年10月1日)和Junio C Hamano (
gitster
)。(由Junio C Hamano --
gitster
--合并至commit bb188d0,2016年10月3日)这个新属性(猜测SHA1缩写值的合理默认值)直接影响Git compute its own version number for release的方式。
frebpwbc2#
这就是所谓的生日问题。
对于小于1/2的概率,碰撞概率可近似为
p ~=(n ~ 2)/(2m)
其中n是项目数,m是每个项目的可能性数。
十六进制字符串的可能性为16 c,其中c是字符数。
对于8个字符和3万次提交
30K ~= 215
p ~=(n2)/(2m)~=((215)2)/(2168)= 230/233 =
增加到12个字符
p ~=(n ~ 2)/(2m)~=((215)~ 2)/(21612)= 230/249 = 2-19
4xy9mtcn3#
这个问题已经得到了解答,但对于任何寻找背后数学的人来说,它被称为 * 生日问题 *(Wikipedia)。
它是关于一个N人的群组中有2个(或更多)人在一年中的同一天生日的概率,类似于仓库中有2个(或更多)git提交的概率,仓库中总共有N个提交具有相同的哈希前缀长度X。
查看概率表,例如,对于长度为8的哈希十六进制字符串,当仓库只有9300个条目(git commits)时,发生冲突的概率达到1%;对于110000个提交,发生冲突的概率为75%;但是如果哈希十六进制字符串长度为12,则100000个提交中发生冲突的概率低于0.1%。
0vvn1miw4#
Git版本2.11(或者2.12?)将包含一个特性,可以根据项目的大小调整短标识符(例如
git log --oneline
)中使用的字符数。一旦使用了这样的Git版本,你的问题的答案可能是“选择Git为git log --oneline
提供的任何长度,都足够安全”。有关详细信息,请参见Changing the default for “core.abbrev”? discussion in Git Rev News edition 20和提交bb188d00f7。
7kqas0il5#
这个问题实际上在Pro Git的第7章中得到了回答:
一般来说,8到10个字符就足够保证项目的唯一性了,最大的Git项目之一Linux内核开始需要40个字符中的12个字符来保持唯一性。
7位数是Git对短SHA的默认值,所以这对大多数项目来说都很好。内核团队已经把他们的SHA值增加了好几倍,正如前面提到的,因为他们有 * 几十万 * 个提交。所以对于你的~ 30 k提交,8或10位数应该是完全合适的。