为什么git hash-object返回与openssl sha1不同的哈希?

时间:2011-03-13 15:50:07

标签: git openssl sha1

背景信息:我已将a file (Audirvana 0.7.1.zip)从code.google下载到我的Macbook Pro(Mac OS X 10.6.6)。

我想验证校验和,该特定文件的校验和发布为862456662a11e2f386ff0b24fdabcb4f6c1c446a(SHA-1)。 git hash-object给了我一个不同的哈希值,但openssl sha1返回了预期的862456662a11e2f386ff0b24fdabcb4f6c1c446a。

以下实验似乎排除了任何可能的下载损坏或换行差异,并表明实际上有两种不同的算法在起作用:

$ echo A > foo.txt
$ cat foo.txt
A
$ git hash-object foo.txt 
f70f10e4db19068f79bc43844b49f3eece45c4e8
$ openssl sha1 foo.txt 
SHA1(foo.txt)= 7d157d7c000ae27db146575c08ce30df893d3a64

发生了什么事?

4 个答案:

答案 0 :(得分:54)

你看到了一个区别,因为git hash-object不只是对文件中的字节进行哈希处理 - 它在文件大小之前加上字符串“blob”,在散列之前加上文件内容的NUL。 Stack Overflow的另一个答案中有更多细节:

或者,为了说服自己,尝试类似的事情:

$ echo -n hello | git hash-object --stdin
b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0

$ printf 'blob 5\0hello' > test.txt
$ openssl sha1 test.txt
SHA1(test.txt)= b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0

答案 1 :(得分:4)

SHA1摘要是通过标题字符串后跟文件数据计算的。标题由对象类型,空格和以十进制为单位的对象长度组成。它通过空字节与数据分开。

所以:

$ git hash-object foo.txt
f70f10e4db19068f79bc43844b49f3eece45c4e8
$ ( perl -e '$size = (-s shift); print "blob $size\x00"' foo.txt \
               && cat foo.txt ) | openssl sha1
f70f10e4db19068f79bc43844b49f3eece45c4e8

这样做的一个结果是“空”树和“空”blob具有不同的ID。那就是:

e69de29bb2d1d6434b8b29ae775ad8c2e48c5391始终表示“空文件” 4b825dc642cb6eb9a060e54bf8d69288fbee4904始终表示“空目录”

你会发现你实际上可以在没有注册对象的新git存储库中执行git ls-tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904,因为它被识别为特殊情况并且从未实际存储过(使用现代Git版本)。相比之下,如果您向repo添加一个空文件,则会存储blob“e69de29bb2d1d6434b8b29ae775ad8c2e48c5391”。

答案 2 :(得分:2)

答案就在这里:

How to assign a Git SHA1's to a file without Git?

git计算文件元数据+内容,而不仅仅是内容。

现在这是一个很好的答案,而且需要注意的是git不是校验和下载的工具。

答案 3 :(得分:1)

Git将对象存储为[对象类型,对象长度,分度(\ 0),内容] 就您而言:

$ echo "A" | git hash-object --stdin
f70f10e4db19068f79bc43844b49f3eece45c4e8

尝试将哈希计算为:

$ echo -e "blob 2\0A" | shasum 
f70f10e4db19068f79bc43844b49f3eece45c4e8  -

请注意使用-e(对于bash shell)并调整换行符的长度。