树对象的格式如下:
tree SIZE\0ENTRIES
SIZE
是树的大小。
ENTRIES
是一个序列,其中每个元素表示树引用的对象。
每个对象条目的格式如下:
MODE NAME\0BSHA
MODE
是:
- 100644 对于普通文件,
- 100755 用于可执行文件,
- 120000 用于符号链接,
- 040000 表示树对象。
NAME
是目录或文件名。
BSHA
是对象 ID 的二进制表示。
关于 OP 的示例,让我们获取对上层树(主分支)的引用:
$ git write-tree
05b217bb859794d08bb9e4f7f04cbda4b207fbe9
虽然我将使用这棵树,但以下内容适用于每棵树。
前 6 个字符 ( 05b217
) 就足够了。
人类可读格式的树内容由下式给出:
$ git ls-tree 05b217
100644 blob aa823728ea7d592acc69b36875a482cdf3fd5c8d rose
您可以替换git ls-tree
为git cat-file -p
.
二进制格式类似于以下给出的:
$ git cat-file tree 05b217
100644 rose ▒▒7(▒}Y*▒i▒hu▒▒▒▒▒\▒%
实际内容也有初始字符串tree [content size]\0
。要获得它,您可以使用 2/38 哈希格式
解压缩将树存储在文件夹中的文件:.git
$ openssl zlib -d -in .git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9
tree 32 100644 rose ▒▒7(▒}Y*▒i▒hu▒▒▒▒▒\▒%
给定存储在树中并可通过 获取的对象ls-tree
,可能会生成使用 awk 脚本存储的(实际)内容:
$ git ls-tree 05b217 | awk -b 'function bsha(asha)\
{patsplit(asha, x, /../); h=""; for(j in x) h=h sprintf("%c", strtonum("0x" x[j])); return(h)}\
{t=t sprintf("%d %s\0%s", $1, $4, bsha($3))} END {printf("tree %s\0%s", length(t), t)}'
tree 32 100644 rose ▒▒7(▒}Y*▒i▒hu▒▒▒▒▒\▒%
为了更好地理解输出,我使用转义序列生成了它的一个版本:
$ git ls-tree 05b217 | awk -b 'function bsha(asha)\
{patsplit(asha, x, /../); h=""; for(j in x) h=h sprintf("%s", "\\x" x[j]); return(h)}\
{t=t sprintf("%d %s\0%s", $1, $4, bsha($3))} END {printf("tree %s\0%s", length(t), t)}'
tree 92 100644 rose \xaa\x82\x37\x28\xea\x7d\x59\x2a\xcc\x69\xb3\x68\x75\xa4\x82\xcd\xf3\xfd\x5c\x8d%
将此输出与之前的输出进行比较git ls-tree 05b217
。
我现在使用不同的方法来 生成树哈希。
使用树的文件存储版本:
$ openssl zlib -d -in .git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9 | shasum
05b217bb859794d08bb9e4f7f04cbda4b207fbe9 *-
使用我的 awk 生成的内容:
$ git ls-tree 05b217 | awk -b 'function bsha(asha)\
{patsplit(asha, x, /../); h=""; for(j in x) h=h sprintf("%c", strtonum("0x" x[j])); return(h)}\
{t=t sprintf("%d %s\0%s", $1, $4, bsha($3))} END {printf("tree %s\0%s", length(t), t)}' | shasum
05b217bb859794d08bb9e4f7f04cbda4b207fbe9 *-
最后是git mktree
命令:
# git ls-tree 05b217 | git mktree
05b217bb859794d08bb9e4f7f04cbda4b207fbe9
获得的哈希值始终相同。