首先,我要说明的是,我知道这种情况发生的可能性极小。我知道制造这种情况几乎是不可能的,并且在实际使用中也非常罕见。这只是一个关于Git内部的假设性问题。
那么,我的问题是:如果两个Git提交哈希值相同会发生什么?首先:
- 提交会成功吗?
- 它能否稍后作为一个分离的头检出?
- 是否可能进行后续提交?
首先,我要说明的是,我知道这种情况发生的可能性极小。我知道制造这种情况几乎是不可能的,并且在实际使用中也非常罕见。这只是一个关于Git内部的假设性问题。
那么,我的问题是:如果两个Git提交哈希值相同会发生什么?首先:
我的旧回答 "如果Git遇到一个Blob的SHA-1冲突会怎样处理?" 仍然适用于提交而不是Blob。
正如torek在评论中提到的那样,Git将所有东西都视为“对象”,每个对象都有自己的SHA1。
(图片来自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年):没有新的提交。
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;
}
return 0
(通过FIXME以及没有失败原因的adjust_shared_perm()
)。