【发布时间】:2015-05-20 08:21:27
【问题描述】:
如何生成 Git 提交 ID 以唯一标识提交?
示例:521747298a3790fde1710f3aa2d03b55020575aa
它是如何工作的?它们仅对每个项目都是独一无二的吗?还是用于全球的 Git 存储库?
【问题讨论】:
标签: git git-svn uniqueidentifier git-commit
如何生成 Git 提交 ID 以唯一标识提交?
示例:521747298a3790fde1710f3aa2d03b55020575aa
它是如何工作的?它们仅对每个项目都是独一无二的吗?还是用于全球的 Git 存储库?
【问题讨论】:
标签: git git-svn uniqueidentifier git-commit
Git 提交 ID 是关于提交的所有重要事项的 SHA-1 hash。我不会一一列举,但这里是重要的...
更改其中任何一项,提交 ID 都会更改。是的,具有相同属性的相同提交将在不同的机器上具有相同的 ID。这有三个目的。首先,这意味着系统可以判断提交是否被篡改。它直接融入架构中。
其次,只需查看提交的 ID,就可以快速比较提交。这使得 Git 的网络协议非常高效。想要比较两个提交以查看它们是否相同?不必发送整个差异,只需发送 ID。
第三,这就是天才,两个具有相同 ID 的提交具有相同的历史。这就是为什么先前提交的 ID 是哈希的一部分。如果一个commit的内容相同但parents不同,那么commit ID必须不同。这意味着在比较存储库时(例如在推送或拉取中),一旦 Git 发现两个存储库之间的共同提交,它就可以停止检查。这使得推拉非常有效。比如……
origin
A - B - C - D - E [master]
A - B [origin/master]
git fetch origin 的网络对话是这样的......
local嘿起源,你有哪些分店?origin我在E有硕士。local我没有E,我有你在B的师父。originB 你说什么?我有 B,它是 E 的祖先。让我把 C、D 和 E 发给你。这也是为什么当你用 rebase 重写一个提交时,它之后的一切都必须改变。这是一个例子。
A - B - C - D - E - F - G [master]
假设您重写 D,只是为了稍微更改日志消息。现在 D 不能再是 D,它必须被复制到我们称为 D1 的新提交中。
A - B - C - D - E - F - G [master]
\
D1
虽然 D1 可以将 C 作为其父级(C 不受影响,提交不知道其子级),但它与 E、F 和 G 断开连接。如果我们将 E 的父级更改为 D1,E 就不能再成为 E。它必须被复制到一个新的提交 E1。
A - B - C - D - E - F - G [master]
\
D1 - E1
以此类推,F 到 F1,G 到 G1。
A - B - C - D - E - F - G
\
D1 - E1 - F1 - G1 [master]
他们都有相同的代码,只是不同的父母(或者在 D1 的情况下,不同的提交消息)。
【讨论】:
您可以通过运行准确查看生成提交 ID 的内容
git cat-file commit HEAD
它会给你类似的东西
tree 07e239f2f3d8adc12566eaf66e0ad670f36202b5
parent 543a4849f7201da7bed297b279b7b1e9a086a255
author Justin Howard <justin.howard@example.com> 1426631449 -0700
committer Justin Howard <justin.howard@example.com> 1426631471 -0700
My commit message
它给你:
Git 接受所有这些并对其进行 sha1 哈希处理。您可以通过运行重现提交 ID
(printf "commit %s\0" $(git cat-file commit HEAD | wc -c); git cat-file commit HEAD) | sha1sum
首先打印字符串commit,后跟一个空格和cat-file 文本块的字节数。然后它将cat-file blob 添加到后面跟一个空字节。然后所有这些都通过sha1sum 运行。
如您所见,此信息中没有任何内容可以识别项目或存储库。这不会导致问题的原因是因为从天文数字上讲,两个不同的提交哈希发生冲突的可能性很小。
【讨论】: