← 解説「treeオブジェクト — ディレクトリ構造をどう表すか」に戻る
サンプルコードで身につける: treeオブジェクト — ディレクトリ構造をどう表すか
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1実際のリポジトリのtreeを覗く
README.md と src/index.js だけの小さなリポジトリで、ルートのtreeを表示した実際の出力です。ファイルは blob、ディレクトリは tree として並んでいます。ファイル名がここで初めて登場する点に注目してください。
# 最新コミットが指すルートtreeを表示する
$ git cat-file -p HEAD^{tree}
100644 blob 058ac035da0ee55124820835a80687441880d04b README.md
040000 tree 7022c258ebb3ee9cab60b56bc770cc9a5997104f src
# src ディレクトリのtreeをさらに辿る
$ git cat-file -p 7022c258ebb3ee9cab60b56bc770cc9a5997104f
100644 blob bf6b8179632b5711ffa21a9869186fae9199d99c index.js
# 葉のblobまで辿り着くと、中身が出てくる
$ git cat-file -p bf6b8179632b5711ffa21a9869186fae9199d99c
console.log("Hello");
# tree → tree → blob と辿れる。これがディレクトリ階層の実体
2treeを木構造として辿ってみる
実際のリポジトリのtreeをデータとして再現し、再帰的に辿ってファイル一覧を復元します。「ある時点のディレクトリ全体」がtreeから完全に決まる、という感覚をつかむためのサンプルです。
Python
3変えていないディレクトリは使い回される(実機での証明)
README.md だけを編集して2回目のコミットをしました。ルートtreeのハッシュは変わりますが、触っていない src の tree は1回目と全く同じハッシュのままです。これが「変更に関係する部分しか増えない」の実例です。
# 1回目のコミットのルートtree
$ git cat-file -p 3a72bb1^{tree}
100644 blob 058ac035da0ee55124820835a80687441880d04b README.md
040000 tree 7022c258ebb3ee9cab60b56bc770cc9a5997104f src
# README.md だけ編集して2回目をコミット
$ git cat-file -p dd2818b^{tree}
100644 blob 4afe36f627e0582eed8581aca4414a6e7e522b37 README.md ← 変わった
040000 tree 7022c258ebb3ee9cab60b56bc770cc9a5997104f src ← 同じ!
# src を一度も触っていないので、そのtreeは共有される
# 2コミットあってもオブジェクトの総数はたったの8個
$ git rev-list --objects --all | wc -l
8
4「毎回全部コピー」と何が違うのか
スナップショットと聞くと毎回まるごと複製する印象を持ちますが、実際に増えるのは変更したファイルから根までの経路だけです。深い階層で1ファイルだけ直したときの増加量を数えて比べます。
Python
5treeのハッシュも中身から決まる
treeもblobと同じで、エントリを並べたバイト列から機械的にIDが決まります。だから中のファイルが1つでも変われば、そのtreeのハッシュも必ず変わります。実際のGitのバイト形式で計算して確かめます。
Python