我看了Hash collision in git 从这看起来,git中两个不同的提交将具有相同的哈希值是非常不可能的。
但是所有提交不仅仅是git呢?我的应用程序使用git,svn,hg - 我可以假设没有不同的提交具有相同的哈希值吗?
现在我正在试图如何阻止我的应用程序从db创建相同的提交来自db中的一个repo的不同forks。 我弄清楚我可以在db unique中做什么哈希列,如果我已经提交了这个哈希 - 只需跳过它。 但我不知道是否有一个很大/很小的机会,我将跳过唯一的提交,而不是已经存在的提交的副本。
答案 0 :(得分:3)
git和mercurial都使用sha1
来生成哈希值,所以我想说两个不同的提交具有相同哈希值的概率,一个来自git,另一个来自mercurial,两个相同的哈希值相同不同的git提交。
Svn不使用哈希来识别提交,而是使用增量修订号,这样你就不会遇到任何碰撞问题
答案 1 :(得分:1)
TL; DR:除非你混合使用VCS,否则你是安全的。
问题中的问题陈述首先是不正确的:
...看起来git中两个不同的提交具有相同的哈希值的可能性非常小。
并且(间接地)导致错误的进一步假设:
但是所有提交不仅仅是git呢?我的应用程序使用git,svn,hg - 我可以假设没有不同的提交具有相同的哈希值吗?
即使所有的VCS都很完美,你也无法做出这样的假设。即使所有VCS都是完美的和使用相同的散列算法,您仍然无法做出这种假设。但是对于你的特定问题,有一个更简单(虽然不完美)的答案。
现在,我试图在数据库中确定如何阻止我的应用程序从创建中提取同一个repo的不同for ... ...
这里要考虑的主要问题是"一个repo"的分支的概念,以及你将如何识别特定的提交。
如果我们查看Git或Mercurial中提交的标识,我们发现 是一个哈希ID。
根据定义,Git中具有相同object-ID 的两个对象是同一个对象,因为Git只存储一次任何对象。这是因为Git的底层存储模型是一个简单的键值存储,其中键是一个哈希ID。任何单个密钥下只存储一个值。
为了允许Git-commit中的四种对象类型,带注释的标记,树和blob-Git将对象的类型存储在所有对象前面的标题中。它假设将字符串commit <size>\0
添加到某些数据之前会产生不同的哈希,而不是将字符串blob <size>\0
添加到相同的数据中。这种假设在很大程度上是正确的,尽管鸽笼原理告诉我们必须有一些数据是错误的。 (在SHA-1良好的情况下,找到产生碰撞的数据对的机会是1 in 2 160 .Stevens等人的研究表明SHA-1不是那么好。)
在任何情况下,Git的底层存储模型意味着一旦一个键具有关联值,该键/值对现在被占用,并且没有与配对>可以再次存储相同的键。因此,如果某些现有密钥 k 存在,并且具有 commit 类型并表示某些提交,则没有任何类型的新对象,其中包含密钥 k 可以添加到存储库数据库中(至少在没有首先使用键 k 删除现有对象的情况下)。
这意味着,如果您假设提交未被删除,并且您在此存储库的任何克隆之前已经看到密钥 k 存在,则任何其他 clone with key k 具有相同的对象。在非常真实的意义上,哈希,换句话说,是对象。
Mercurial不一定是这种情况。 Mercurial的数据库可以存储具有重复键的新提交(与每个对象关联的简单本地序列号可以消除它们的歧义)。但是,这样的提交永远不会从一个存储库转移到另一个存储库(并且可能会导致其他问题),因此如果存储库将被分发,您肯定可以解决问题。
目前,Git和Mercurial都使用SHA-1,但他们以不同的方式使用它们。也就是说,计算散列的输入消息在Git和Mercurial中不同。 这个的意思是,如果你有&#34;分叉&#34; G (通过Git存储)和 M (通过Mercurial存储)代表相同的存储库,键 k G G 中的 (数字上)与 k M 中的<键无关< EM>中号
因此,如果允许两个不同的分支使用两个不同的基础VCS,则不能假设两个不同的密钥代表两个不同的对象,也不能假设两个相同的密钥代表同一个对象。但是,如果将它们约束到相同的 VCS,则可以进行此假设。
(SVN根本没有通过哈希来识别提交。由于SVN存储库是集中式的,它们可以并且确实使用一个简单的唯一整数来表示每个提交。但是,通过将SVN存储库转换为Git存储库,您可以强制使用Git限制:您现在拥有一个存储库,可以满足两个 VCS所施加的任何限制。如果有人向SVN存储库添加了一个无法在Git存储库中正确表示的新提交,它就永远不会进入Git存储库。)