Dev Study
← Gitの内部構造から理解する コース

4. コミットハッシュとtreeの対応 — スナップショットと親への参照

blobとtreeで「ある時点のディレクトリ全体」を表せるようになりました。commitは、そのスナップショット1つに、誰がいつ何のために作ったかというメタデータと、直前のコミットへの参照を添えたものです。

① commitオブジェクトの中身は数行のテキスト

git cat-file -p でコミットを表示したところ
tree 7ed5c15d…この時点のディレクトリ全体を指す(必ず1つ)
parent 0978f6e0…直前のコミットを指す
author / committer名前・メールアドレス・タイムスタンプ
(空行) + コミットメッセージ
  • ・commitはこのテキスト全体のSHA-1で識別される
  • ・最初のコミットには parent 行がない(履歴の起点)
  • ・マージコミットは parent 行を2つ持つ

commitが持つtreeは1つだけです。「このコミットの時点でのファイル全体の姿」がその1つのtreeで完全に決まります。

② 履歴は「親をたどる連結リスト」になっている

commitがparentで繋がる様子
commit C(最新)parent → B
parent をたどる
commit Bparent → A
parent をたどる
commit A(最初)parent 行なし = 終端
  • ・矢印は必ず「新しい → 古い」の向き。子から親は辿れるが、逆は辿れない
  • ・親を持たないコミットに到達したら、そこが履歴の始まり
  • ・マージがあると分岐が合流するので、正確には有向非巡回グラフ(DAG)になる

git log が過去へさかのぼれるのは、この parent の鎖をたどっているからです。「未来のコミット一覧」が存在しないのも、矢印が片方向だからです。

③ コミットハッシュは履歴全体を封じ込めている

ハッシュが何を含んでいるか
commit C のハッシュ
計算に含まれるもの
tree のハッシュ= 全ファイルの中身
parent のハッシュ= それ以前の全履歴
作者・日時・メッセージ
  • ・親のハッシュはさらにその親のハッシュを含んでいる(再帰的)
  • ・つまり最新のコミットハッシュ1つで、履歴全体が確定する
  • ・過去のコミットを1文字でも書き換えると、それ以降すべてのハッシュが変わる

この構造をハッシュチェーンと呼びます。後の rebase のレッスンで「なぜ履歴を書き換えるとハッシュが総取り替えになるのか」が、ここから直接説明できます。

サンプルコードで身につける(5本) →

学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。

公式ドキュメントで詳しく ↗