Gitは内部でどのように動いているのか:オブジェクト、ツリー、そしてBlob
私たちは毎日git add、git commit、git pushを使っています。しかし、.gitフォルダの中を覗いたことはありますか?
Gitの内部を理解することで、「魔法」の謎が解け、はるかに自信を持って使えるようになります(そしてマージコンフリクトの解決も上手になります!)。
本質的に、Gitは**コンテンツアドレス指定ファイルシステム(Content-addressable filesystem)**です。理想的には、キーバリューストアです:
- Key: コンテンツのSHA-1ハッシュ。
- Value: コンテンツそのもの。
Gitが履歴を保存するために使用する3つの主要なオブジェクトを見てみましょう。
1. Blob(Binary Large Object)
ファイルをgit addすると、Gitはそのファイルの内容を取得し、Blobとして保存します。
- ファイル名は保存せず、内容のみを保存します。
- 2つのファイルの内容が完全に同じであれば、同じBlobを共有します(重複排除!)。
git cat-fileコマンドで確認できます:
$ echo "hello" | git hash-object -w --stdin ce013625030ba8dba906f756967f9e9ca394464a
そのハッシュ値がキーになります。
2. ツリー(Tree)
では、ファイル名はどこに保存されるのでしょうか?Treeオブジェクトの中です。
Treeはディレクトリのようなものです。以下の情報のリストを含んでいます:
- ファイル権限(例:
100644) - オブジェクトタイプ(
blobまたはtree) - SHA-1ハッシュ
- ファイル名
Treeをフォルダ構造のスナップショットと考えてください。
100644 blob ce0136... hello.txt
100644 blob 9a8b7c... README.md
040000 tree 3b1c2d... src
3. コミット(Commit)
最後に、Commitオブジェクトがあります。
コミットは、特定のTree(その時点のプロジェクトのスナップショット)を指し示し、メタデータを追加する単なるラッパーです:
- 作成者(Author)とコミッター(Committer)
- 日付
- コミットメッセージ
- 親コミットハッシュ(Parent Commit hash)
各コミットが親を指し示すため、これらは連結リスト(正確には有向非巡回グラフ - DAG)を形成します。
tree 3b1c2d...
parent 8a9b0c...
author John Doe <[email protected]>
committer John Doe <[email protected]>
Initial commit
オブジェクト間の関係を可視化
graph TD subgraph Commit C[Commit Object] -->|Points to| T[Tree Object] C -->|Points to| P[Parent Commit] end subgraph Tree T -->|Contains| B1[Blob: hello.txt] T -->|Contains| B2[Blob: README.md] T -->|Contains| T2[Tree: src] end subgraph Blob B1 -->|Content| Content1["hello"] B2 -->|Content| Content2["# Readme"] end
すべてをまとめると
git commitを実行するときに起こること:
- Gitは変更されたファイルに対してBlobを作成します。
- Gitはプロジェクト構造を表すTreeを作成します。
- Gitは、そのTreeと以前のコミットを指すCommitオブジェクトを作成します。
- ブランチポインタ(例:
main)がこの新しいコミットハッシュに移動します。
なぜこれが重要なのか
- Gitは不変(Immutable)です: オブジェクトが一度作成されると、決して変更されません。履歴を「修正」することは、実際には新しいオブジェクトを作成することです。
- 安価なブランチ作成: ブランチは、コミットハッシュを1つ含む40バイトの小さなファイルにすぎません。ブランチの作成にはコストがかかりません。
- 完全性: SHA-1ハッシュのおかげで、データの1ビットでも変わればIDが変わります。検出されずに履歴を改ざんすることは不可能です。
次に「detached HEAD」状態に陥ったときは、思い出してください:あなたは単にブランチ名のラベルが付いていないコミットオブジェクトを指しているだけなのです!
TechGitVCSInternals
関連ツールを見る
Pockitの無料開発者ツールを試してみましょう
PDF分割
必要なページだけを取り出せます。大きなドキュメントを分割したり、特定のページだけを安全に抽出して保存できます。
使ってみる
PDF画像変換
PDFを画像として活用しましょう。ドキュメントの各ページを高画質なJPGやPNGに変換してダウンロードできます。
使ってみる
Base64変換
データを安全に変換・復元。テキストやファイルをBase64形式にエンコード、またはデコードします。サーバー通信はありません。
使ってみる
コード整形・圧縮
1行にギュッと詰まった圧縮コードを読みやすく整形したり、本番用にサイズを小さくしたり。JS、CSS、HTML対応。ブラウザで完結するからコードは外に出ません。
使ってみる
パスワード生成
強力なセキュリティを手に入れましょう。解読困難な安全なパスワードを、ブラウザ内で即座に生成します。
使ってみる
UUID生成
重複しないIDが必要ですか?開発やテストに使えるユニークなUUID(v4)を、安全に大量生成できます。
使ってみる