44

Git ツリー オブジェクトのコンテンツの形式は何ですか?

ブロブ オブジェクトの内容は ですがblob [size of string] NUL [string]、ツリー オブジェクトの場合はどうでしょうか。

4

5 に答える 5

44

ツリー オブジェクトの形式:

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 進文字列に変換しました。

于 2014-02-06T09:48:37.710 に答える
17

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 ツリーは次のヘッダーで始まります。

  1. リテラル文字列tree
  2. SPACE (つまり、バイト0x20)
  3. 圧縮されていないコンテンツの ASCII エンコードされた 10 進数の長さ

NUL (つまり、バイト0x00) ターミネータの後に、ツリーには次の形式のエントリが 1 つ以上含まれます。

  1. ASCII エンコードの 8 進モード
  2. スペース
  3. 名前
  4. ヌル
  5. 符号なし 20 バイトとしてエンコードされた SHA1 ハッシュ

次に、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
于 2016-03-09T21:03:16.950 に答える
3

おっしゃる通り、Pro Git は構造をよく説明してくれます。きれいに印刷されたツリーを表示するには、次を使用します。

git cat-file -p 4c975c5f5945564eae86d1e933192c4a9096bfe5

同じツリーを未加工の非圧縮形式で表示するには、次を使用します。

git cat-file tree 4c975c5f5945564eae86d1e933192c4a9096bfe5

構造は本質的に同じで、ハッシュはバイナリおよび null で終わるファイル名として保存されます。

于 2013-02-10T01:48:14.970 に答える