如果两个Git提交具有相同的SHA-1哈希值,会发生什么?

24

首先,我要说明的是,我知道这种情况发生的可能性极小。我知道制造这种情况几乎是不可能的,并且在实际使用中也非常罕见。这只是一个关于Git内部的假设性问题。

那么,我的问题是:如果两个Git提交哈希值相同会发生什么?首先:

  • 提交会成功吗?
  • 它能否稍后作为一个分离的头检出?
  • 是否可能进行后续提交?

1
这里有一些讨论,但我认为它并没有很好地回答这个问题:https://dev59.com/t2kv5IYBdhLWcg3wqimS - mipadi
我确实看到了,但它似乎讨论的是文件哈希而不是提交哈希。 - Ben
1
是的,大多数答案都集中在Git中哈希部分。不过,这里有一个关于Git邮件列表的讨论链接:http://thread.gmane.org/gmane.comp.version-control.git/26106/focus=26170 - mipadi
1
@CommuSoft:是的,这一点已经在您上面的评论中得到了注意并作出了回应。 - mipadi
2
无论是“文件”还是“提交”,这并不重要,因为在内部,Git 只将所有东西视为“对象”。如果两个对象具有相同的哈希值,则它们在 Git 看来是相同的对象,只有第一个进入的对象才会被记录下来,因为在此之后,第二个具有哈希冲突的对象,Git 就会假定它是第一个对象。我可以看出,当尝试写入新对象但实际上访问了“错误”类型的现有对象时,这可能会导致命令出现一些问题,但从根本上讲,您的存储库只是以某种方式变成只读状态。 - torek
显示剩余2条评论
2个回答

9

我的旧回答 "如果Git遇到一个Blob的SHA-1冲突会怎样处理?" 仍然适用于提交而不是Blob。
正如torek在评论中提到的那样,Git将所有东西都视为“对象”,每个对象都有自己的SHA1。

https://git-scm.com/book/en/v2/book/10-git-internals/images/data-model-4.png

(图片来自Git内部-Git参考章节,ProGit Book v2

虽然提交可能不会成功(git-commit-tree.c中有几个检查),但您还必须考虑在仓库A和B中创建具有相同SHA1(并且某种程度上具有不同内容)的两个提交的情况...而且仓库A正在获取仓库B!
提交8685da4(2007年3月,git 1.5.1)已经解决了这个问题,因此提取将失败。
提交0e8189e(2008年10月,git 1.6.1)提到了这一点,使用index V2

SHA1引用损坏并实际匹配另一个具有相同大小的对象的SHA1的几率(delta标头存储要应用于的基本对象的预期大小)几乎为零。

在解包对象时,它仍然实现了紧缩对象CRC检查。

Git代码提到了finalize_object_file()函数责备没有最近的修改,大部分代码可以追溯到Git的开端(2005年):没有新的提交。


2
根据源代码(在git v2.17中存在),如果提交导致已经存在的sha1,这就是在Linux上会发生的事情(对于其他操作系统可能会有所不同)。
该提交是否成功?
是和否:`git commit`命令将返回成功,但新的提交对象将不会被创建。
它以后可以作为分离的头检出吗?
不可以。
参考:文件sha1-file.c(提交`fc1395f4a491a7da46a446233531005634eb979d`)。
int finalize_object_file(const char *tmpfile, const char *filename)
{
    int ret = 0;

    if (object_creation_mode == OBJECT_CREATION_USES_RENAMES)
        goto try_rename;
    else if (link(tmpfile, filename))
        ret = errno;

    /*
     * Coda hack - coda doesn't like cross-directory links,
     * ...
     */
    if (ret && ret != EEXIST) {
    try_rename:
        if (!rename(tmpfile, filename))
            goto out;
        ret = errno;
    }
    unlink_or_warn(tmpfile);
    if (ret) {
        if (ret != EEXIST) {
            return error_errno("unable to write sha1 filename %s", filename);
        }
        /* FIXME!!! Collision check here ? */
    }

out:
    if (adjust_shared_perm(filename))
        return error("unable to set permission to '%s'", filename);
    return 0;
}

链接失败并出现EEXIST错误,临时文件被删除,代码继续执行直到return 0(通过FIXME以及没有失败原因的adjust_shared_perm())。

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