1

首先初始化一个包含名为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
我哪里错了?

4

3 回答 3

3

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
于 2012-12-20T17:00:19.027 回答
3

树中的对象 ID 未以该格式存储。看一看:

git cat-file tree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 | od -c

相反,树数据是 的序列<mode> SP <filename> NUL <hash>,其中<mode>是字符串形式模式,并且<hash>是 20 字节的 SHA1。

于 2012-12-20T17:14:33.257 回答
2

树对象的格式如下:

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-treegit 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    

获得的哈希值始终相同。

于 2016-05-08T00:25:02.617 回答