在上一篇文章中,将了数据工具、树工具和提交工具三种Git工具,每种工具管帐算出一个hash值。那么,Git是如何计较出Git工具的hash值?本文的内容就是来解答这个问题。
Git工具的hash要领
Git中的数据工具、树工具和提交工具的hash要领道理是一样的,可以描写为:
header = "<type> " + content.length + "\0" hash = sha1(header + content)
上面公式暗示,Git在计较工具hash时,首先会在工具头部添加一个header
。这个header
由3部门构成:第一部门暗示工具的范例,可以取值blob
、tree
、commit
以别离暗示数据工具、树工具、提交工具;第二部门是数据的字节长度;第三部门是一个空字节,用来将header
和content
脱离开。将header
添加到content
头部之后,利用sha1
算法计较出一个40位的hash值。
在手动计较Git工具的hash时,有两点需要留意:
1.header
中第二部门关于数据长度的计较,必然是字节的长度而不是字符串的长度;
2.header + content
的操纵并不是字符串级此外拼接,而是二进制级此外拼接。
各类Git工具的hash要领沟通,昆山软件开发,差异的在于:
1.头部范例差异,数据工具是blob
,树工具是tree
,提交工具是commit
;
2.数据内容差异,数据工具的内容可以是任意内容,而树工具和提交工具的内容有牢靠的名目。
接下来别离讲数据工具、树工具和提交工具的详细的hash要领。
数据工具
数据工具的名目如下:
blob <content length><NULL><content>
从上一篇文章中我们知道,利用git hash-object
可以计较出一个40位的hash值,譬喻:
$ echo -n "what is up, doc?" | git hash-object --stdin bd9dbf5aae1a3862dd1526723246b20206e5fc37
留意,劳务派遣管理系统,上面在echo
后头利用了-n
选项,用来阻止自动在字符串末端添加换行符,不然会导致实际传给git hash-object
是what is up, doc?\n
,而不是我们直观认为的what is up, doc?
。
为验证前面提到的Git工具hash要领,我们利用openssl sha1
来手动计较what is up, doc?
的hash值:
$ echo -n "blob 16\0what is up, doc?" | openssl sha1 bd9dbf5aae1a3862dd1526723246b20206e5fc37
可以发明,手动计较出的hash值与git hash-object
计较出来的一模一样。
在Git工具hash要领的留意事项中,提到header
中第二部门关于数据长度的计较,必然是字节的长度而不是字符串的长度。由于what is up, doc?
只有英文字符,在UTF8中刚好字符的长度和字节的长度都便是16,很容易将这个长度误解为字符的长度。假设我们以中文
来试验:
$ echo -n "中文" | git hash-object --stdin efbb13322ba66f682e179ebff5eeb1bd6ef83972 $ echo -n "blob 2\0中文" | openssl sha1 d1dc2c3eed26b05289bddb857713b60b8c23ed29
我们可以看到,git hash-object
和openssl sha1
计较出来的hash值基础纷歧样。这是因为中文
两个字符作为UTF名目存储后的字符长度不是2,详细是几多呢?可以利用wc
来计较:
$ echo -n "中文" | wc -c 6
中文
字符串的字节长度是6,从头手动计较发明得出的hash值就能对应上了:
$ echo -n "blob 6\0中文" | openssl sha1 efbb13322ba66f682e179ebff5eeb1bd6ef83972
树工具
树工具的内容名目如下:
tree <content length><NUL><file mode> <filename><NUL><item sha>...
需要留意的是,<item sha>
部门是二进制形式的sha1码,而不是十六进制形式的sha1码。