Git ツリー オブジェクトのコンテンツの形式は何ですか?
ブロブ オブジェクトの内容は ですがblob [size of string] NUL [string]
、ツリー オブジェクトの場合はどうでしょうか。
Git ツリー オブジェクトのコンテンツの形式は何ですか?
ブロブ オブジェクトの内容は ですがblob [size of string] NUL [string]
、ツリー オブジェクトの場合はどうでしょうか。
ツリー オブジェクトの形式:
tree [content size]\0[Entries having references to other trees and blobs]
他のツリーとブロブへの参照を持つ各エントリの形式:
[mode] [file/folder name]\0[SHA-1 of referencing blob or tree]
ツリー オブジェクトを収縮させるスクリプトを作成しました。次のように出力します。
tree 192\0
40000 octopus-admin\0 a84943494657751ce187be401d6bf59ef7a2583c
40000 octopus-deployment\0 14f589a30cf4bd0ce2d7103aa7186abe0167427f
40000 octopus-product\0 ec559319a263bc7b476e5f01dd2578f255d734fd
100644 pom.xml\0 97e5b6b292d248869780d7b0c65834bfb645e32a
40000 src\0 6e63db37acba41266493ba8fb68c76f83f1bc9dd
モードの最初の文字としての数字の 1 は、ブロブ/ファイルへの参照であることを示します。上記の例では、pom.xml は blob で、その他はツリーです。
\0
きれいに印刷するために、後で新しい行とスペースを追加したことに注意してください。通常、すべてのコンテンツに改行はありません。また、見やすくするために、20 バイト (つまり、ブロブとツリーを参照する SHA-1) を 16 進文字列に変換しました。
BNF のようなパターンとして表現される git ツリーには、次の形式のデータが含まれます。
(?<tree> tree (?&SP) (?&decimal) \0 (?&entry)+ )
(?<entry> (?&octal) (?&SP) (?&strnull) (?&sha1bytes) )
(?<strnull> [^\0]+ \0)
(?<sha1bytes> (?s: .{20}))
(?<decimal> [0-9]+)
(?<octal> [0-7]+)
(?<SP> \x20)
つまり、git ツリーは次のヘッダーで始まります。
tree
0x20
)NUL (つまり、バイト0x00
) ターミネータの後に、ツリーには次の形式のエントリが 1 つ以上含まれます。
次に、Git はツリー データをzlib のdeflate にフィードして、コンパクトなストレージにします。
git blob は匿名であることを忘れないでください。Git ツリーは、ブロブや他のツリーなどの他のコンテンツの SHA1 ハッシュに名前を関連付けます。
実例として、git の v2.7.2 タグに関連付けられたツリーを考えてみましょう。これは GitHub で参照できます。
$ git rev-parse v2.7.2^{tree}
802b6758c0c27ae910f40e1b4862cb72a71eee9f
以下のコードでは、ツリー オブジェクトが "loose" 形式である必要があります。パックファイルから単一の生オブジェクトを抽出する方法がわからないため、最初git unpack-objects
にクローンから新しいリポジトリへのパック ファイルを実行しました。.git
これにより、約 90 MB から始まったディレクトリが約 1.8 GB に拡張されたことに注意してください。
更新:単一のオブジェクトをアンパックする方法を示してくれた max630 に感謝します。
#! /usr/bin/env perl
use strict;
use warnings;
use subs qw/ git_tree_contents_pattern read_raw_tree_object /;
use Compress::Zlib;
my $treeobj = read_raw_tree_object;
my $git_tree_contents = git_tree_contents_pattern;
die "$0: invalid tree" unless $treeobj =~ /^$git_tree_contents\z/;
die "$0: unexpected header" unless $treeobj =~ s/^(tree [0-9]+)\0//;
print $1, "\n";
# e.g., 100644 SP .gitattributes \0 sha1-bytes
while ($treeobj) {
# /s is important so . matches any byte!
if ($treeobj =~ s/^([0-7]+) (.+?)\0(.{20})//s) {
my($mode,$name,$bytes) = (oct($1),$2,$3);
printf "%06o %s %s\t%s\n",
$mode, ($mode == 040000 ? "tree" : "blob"),
unpack("H*", $bytes), $name;
}
else {
die "$0: unexpected tree entry";
}
}
sub git_tree_contents_pattern {
qr/
(?(DEFINE)
(?<tree> tree (?&SP) (?&decimal) \0 (?&entry)+ )
(?<entry> (?&octal) (?&SP) (?&strnull) (?&sha1bytes) )
(?<strnull> [^\0]+ \0)
(?<sha1bytes> (?s: .{20}))
(?<decimal> [0-9]+)
(?<octal> [0-7]+)
(?<SP> \x20)
)
(?&tree)
/x;
}
sub read_raw_tree_object {
# $ git rev-parse v2.7.2^{tree}
# 802b6758c0c27ae910f40e1b4862cb72a71eee9f
#
# NOTE: extracted using git unpack-objects
my $tree = ".git/objects/80/2b6758c0c27ae910f40e1b4862cb72a71eee9f";
open my $fh, "<", $tree or die "$0: open $tree: $!";
binmode $fh or die "$0: binmode: $!";
local $/;
my $treeobj = uncompress <$fh>;
die "$0: uncompress failed" unless defined $treeobj;
$treeobj
}
私たちの哀れな男のgit ls-tree
行動を見てください。出力は、tree
マーカーと長さを出力することを除いて同じです。
$ diff -u <(cd ~/src/git; git ls-tree 802b6758c0) <(../rawtree) --- /dev/fd/63 2016-03-09 14:41:37.011791393 -0600 +++ /dev/fd/62 2016-03-09 14:41:37.011791393 -0600 @@ -1,3 +1,4 @@ +木 15530 100644 ブロブ 5e98806c6cc246acef5f539ae191710a0c06ad3f .gitattributes 100644 ブロブ 1c2f8321386f89ef8c03d11159c97a0f194c4423 .gitignore 100644 ブロブ e5b4126bec557db55924b7b60ed70349626ea2c4 .mailmap
おっしゃる通り、Pro Git は構造をよく説明してくれます。きれいに印刷されたツリーを表示するには、次を使用します。
git cat-file -p 4c975c5f5945564eae86d1e933192c4a9096bfe5
同じツリーを未加工の非圧縮形式で表示するには、次を使用します。
git cat-file tree 4c975c5f5945564eae86d1e933192c4a9096bfe5
構造は本質的に同じで、ハッシュはバイナリおよび null で終わるファイル名として保存されます。