首先初始化一个包含名为rose
的文件的repo$: echo sweet > rose
$: git init
$: git add .
$: find .git/objects/ -type f
.git/objects/aa/823728ea7d592acc69b36875a482cdf3fd5c8d
$: git commit -m "rose"
$: find .git/objects/ -type f -printf "%h%f %s\n"
.git/objects/05b217bb859794d08bb9e4f7f04cbda4b207fbe9 49
.git/objects/aa823728ea7d592acc69b36875a482cdf3fd5c8d 21
.git/objects/665d02ccbacdde1c0f2eecde01fbf47144ddd492 124
然后我想破坏blob并看看如何生成树对象的id
echo -e "tree 21\0100644 rose\0aa823728ea7d592acc69b36875a482cdf3fd5c8d"|sha1sum
打印的内容不是05b217bb859794d08bb9e4f7f04cbda4b207fbe9
我哪里错了?
答案 0 :(得分:3)
树中的对象ID不以该格式存储。看看:
git cat-file tree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 | od -c
而是树数据是<mode> SP <filename> NUL <hash>
的序列,其中<mode>
是字符串格式,<hash>
是20字节的SHA1。
答案 1 :(得分:2)
echo
会插入换行符,除非您指定-n
(省略换行符)标记。
此外,blob ID不是以ASCII格式存储,而是以二进制值存储。这导致对象大小为32(而不是21)。
以下命令将为您提供正确的输出:
echo -en 'tree 32\x00100644 rose\x00\xaa\x82\x37\x28\xea\x7d\x59\x2a\xcc\x69\xb3\x68\x75\xa4\x82\xcd\xf3\xfd\x5c\x8d' | sha1sum
答案 2 :(得分:1)
树对象的格式如下:
tree SIZE\0ENTRIES
SIZE
是树的大小
ENTRIES
是一个序列,其中每个元素表示树引用的对象
每个对象条目的格式如下:
MODE NAME\0BSHA
MODE
是:
NAME
是目录或文件名
BSHA
是对象ID的二进制表示。
关于OP的例子,让我们得到对上层树(master分支)的引用:
$ 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
获得的哈希值始终相同。