Dev Study
← コース一覧

Gitの内部構造から理解する

「なぜコンフリクトが起きるのか」「なぜrebaseで履歴が変わるのか」。コマンドを先に覚えると、こうした疑問にぶつかったとき迷子になります。このコースはハッシュ化から出発し、blob・tree・commitという3種類のオブジェクトと、ブランチの正体である「40文字が書かれた41バイトのファイル」まで積み上げます。ブランチ切り替えが一瞬で終わる理由も、マージがポインタの付け替えで済む場合がある理由も、図と擬似体験で自分で説明できるようになります。

公式ドキュメント: Pro Git — Git Internals ↗

第1部 ハッシュという土台

  1. 1
    ハッシュ化 — 同じ内容なら必ず同じ40文字になる
    Gitのすべての仕組みは、たった1つの性質の上に建っています。「中身を入れると、40文字の文字列が出てくる。同じ中身なら必ず同じ文字列になり、1文字でも違えば全く別の文字列になる」という性質です。
  2. 2
    ハッシュ値とblobの対応 — Gitはファイル名ではなく中身を保存する
    ここが最初の山場です。Gitが保存しているのは「ファイル」ではなく「中身」であり、ファイル名はそこに含まれていません。この事実が、後で出てくるほとんどの挙動の説明になります。

第2部 スナップショットの構造

  1. 3
    treeオブジェクト — ディレクトリ構造をどう表すか
    blobは中身しか持っていませんでした。「どのファイル名で、どの階層に置かれているか」を担当するのが tree です。treeは1つのディレクトリに対応します。
  2. 4
    コミットハッシュとtreeの対応 — スナップショットと親への参照
    blobとtreeで「ある時点のディレクトリ全体」を表せるようになりました。commitは、そのスナップショット1つに、誰がいつ何のために作ったかというメタデータと、直前のコミットへの参照を添えたものです。

第3部 ブランチとHEAD

  1. 5
    ブランチの正体 — 40文字が書かれた41バイトのファイル
    ここまでで、コミットの鎖ができました。しかし40文字のハッシュを人間が覚えるのは無理です。そこでGitは「名前 → コミットハッシュ」の対応を作ります。それがブランチで、実体は驚くほど単純です。
  2. 6
    擬似体験 — 手を動かしてオブジェクトが生まれる瞬間を見る
    ここまで図で見てきた blob・tree・commit・ref が、実際の操作でどう増えていくかを体験します。下のパネルでファイルを編集し、git add と git commit を押してください。右側のオブジェクトDBが変化します。

第4部 日常の操作が腑に落ちる

  1. 7
    git add の正体 — ステージは「次のtreeの下書き」
    新卒がまず戸惑うのが「なぜcommitの前にaddが要るのか」です。内部構造から見ると、addとcommitはまったく別の仕事をしています。
  2. 8
    マージ — なぜポインタの付け替えで済むことがあるのか
    マージには大きく2つの場合があります。どちらになるかは「履歴が分岐しているかどうか」だけで決まり、内部構造を知っていれば事前に予測できます。
  3. 9
    コンフリクト — なぜ起きるのか、なぜ人間が要るのか
    コンフリクトは「Gitの不具合」でも「操作を間違えた罰」でもありません。3-way mergeの構造から、原理的に自動判断できないケースがあるというだけです。
  4. 10
    rebase — なぜ履歴が「書き換わる」のか
    「rebaseすると履歴が変わる」「共有ブランチでrebaseするな」とよく言われます。commitオブジェクトの構造を知っていれば、この理由は自分で導けます。
  5. 11
    detached HEAD と「消えたコミット」— 参照されないだけで残っている
    新卒が最も慌てるのが「detached HEAD」の警告と、コミットが消えたように見える場面です。ここも参照の構造で説明がつきますし、多くの場合コミットは消えていません。
  6. 12
    push と fetch — リモートとの間で何が運ばれるのか
    最後に、リモートリポジトリ(GitHub、GitLab、AWS CodeCommitなど)との同期を見ます。ホスティング先が変わっても、運ばれるものは同じです。