1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

.gitフォルダの中身からGitを理解する

1
Last updated at Posted at 2026-05-06

.gitフォルダについて

GitHubなどからリポジトリをローカルにCloneしてくると必ず存在しているこのフォルダ。
中身を見てみるとGitの仕組みが見えてきました。
image.png

まずは用語定義

Gitを理解するうえでデータを管理する領域の用語定義と、各領域の役割を説明します。

用語定義.png

.gitフォルダ構成

.gitフォルダ内にあるフォルダ、ファイルの概要は以下の通りです。

フォルダ構成概要.png

今回掘り下げる対象

Gitのメインのサービスに関係が深いファイルについて掘り下げます。

  • HEAD
  • index
  • objects/

HEAD

現在チェックアウトしているブランチ(またはコミット)を示すポインタです。
1行だけ 記載されているテキストファイルとなっています。

コミットをチェックアウトしている場合 【コミットID:fa96cc~{省略}】
fa96ccd4cf97bcc73fb8593af0cb0176ec5ad357

 

「test-branch」というブランチをチェックアウトしている場合
ref: refs/heads/test-branch

refに記載されている内容は相対パスになっており、
2. オブジェクトと参照の管理 .git/refsと対応します。
.git / refs / heads / {ブランチ名}には、そのブランチの最新コミットIDが記載されます。
image.png

.git/refs/heads/test-branchの中身
cfadb026edb6f828ab4b2f536eea45cfb73cecac

※Gitの最適化により .git/packed-refs にまとめられる場合もありますが、この記事では省略します。

index

ステージングエリア(インデックス)の内容を管理するファイルです。
中身の大半はバイナリになっているため、テキストエディタで確認することはできません。

代わりに以下のコマンドを実行することで、このファイルの一部を確認することができます。

コマンド
git ls-files --stage
実行結果
100644 8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b91 0       .gitattributes
100644 b2c3d4e5f6a7b8c9d0e1f234567890abcdef1234 0       README.md
100644 9e8d7c6b5a4f3e2d1c0b9a8e7d6c5b4a3210fedc 0       hello.txt
100644 1a23c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1 0       src/app.py
項目名 備考
ファイルモード 100644 実行権限やファイル区分
(通常ファイル、シンボリックリンクなど)
【重要】blob ID adb287dbf7e698243d0e492b44920afffa1c3244 ファイルの 内容 そのものに付与されたID
stage番号 0 基本0が設定される
コンフリクト時には同じファイルパスに対して別の番号が振られる
ファイルパス memo.md -

このindexファイルの中にはステージングエリア内のファイルの記載内容は保管されていません。

ですが、ワークツリーとステージングエリアとの差分を表示する機能を実現するためには ステージングエリア内のファイルの記載内容 を管理しておかないとこの機能は実現できません。
差分.png

このファイルの内容は .git/objects というフォルダの中で管理されています。
(詳細は後述)

objects

このフォルダ配下には Gitオブジェクト と呼ばれるファイルが配置されます。
Gitオブジェクトは以下の4種類に細分化されます。

Gitオブジェクトの保存形式は looseオブジェクト と packedオブジェクト の2種類存在しています。
 looseオブジェクト :各オブジェクトファイルを個別で管理する状態
 packedオブジェクト :複数のlooseオブジェクトを集約・圧縮し容量を削減した状態

ローカルの作業で生成されるGitオブジェクトは基本的にlooseオブジェクトで管理され、特定のタイミングでpackedオブジェクトに集約されます。
(チェックアウトしてきた時点ではpackedオブジェクトになっていることが多い)

■ Gitオブジェクトについて

それぞれのオブジェクトファイル名は、オブジェクトの情報をハッシュ化することで生成したIDが使用されます。
通常のリポジトリでは SHA-1(40桁) を使用してハッシュ化することが一般的ですが、SHA-256(64桁) を使用するケースもあります。

オブジェクトID = SHA-1 or SHA-256(
  オブジェクト種別 + " " + サイズ + "\0" + 実データ
)

オブジェクトIDの構成要素にファイル名は含まれません
そのためblobオブジェクトを生成する際、ファイルの中身が同じであればファイル名が異なっていても同じblobオブジェクトを参照します。

各オブジェクトファイルの実態は.git/objectsにて、各オブジェクトIDの
 ・先頭2桁:フォルダ名
 ・3桁目以降:ファイル名(拡張子なし)
のように管理されます。

【補足】先頭2桁でフォルダを作成する理由

1つのディレクトリに大量のファイルが作成されることを避けるためです。
リポジトリが大きくなるほど、Gitオブジェクトはどんどん増えていきます。

SHA-1で生成された文字列はランダム性が強いため、文字列の一部をそのままフォルダ名に流用することで格納場所の偏りを防いでいます。
※「数学的に必ず均等に散らばる」というわけではなく、あくまで偏りにくくなるというレベルです

SHA-1によって生成される文字列に使用されるのは0~fまでの16種類となっており、2桁にすることで最大256個のフォルダに分散することができます。
これを3桁にすると4096通りになってしまうため、フォルダが多すぎてしまいます。

各Gitオブジェクトの中身について

ファイルの中身はzlib圧縮されているバイナリデータのため、テキストエディタから直接中身を確認することはできません。

commitオブジェクトの中身
commit 189
tree cdef1234567890abcdef1234567890abcdef1234
parent 1111222233334444555566667777888899990000
author Alice <alice@example.com> 1715000000 +0900
committer Alice <alice@example.com> 1715000000 +0900

docs: add README and initial files 
項目 意味
オブジェクト種別 commit コミットオブジェクト
サイズ 189 本文部分のバイト数
tree ID cdef1234567890abcdef1234567890abcdef1234 このコミット時点のディレクトリ・ファイル構成
parentID 1111222233334444555566667777888899990000 直前のコミットID
初回コミットの場合は項目自体存在しない
マージコミットの場合は項目が複数存在する
author Alice <alice@example.com> 変更を作成した人
committer Alice <alice@example.com> コミットとして記録した人
日時 1715000000 +0900 コミット日時
コミットメッセージ add README and initial files コミット内容の説明
treeオブジェクトの中身
tree 96
100644 blob 8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b91 .gitattributes
100644 blob b2c3d4e5f6a7b8c9d0e1f234567890abcdef1234 README.md
100644 blob 9e8d7c6b5a4f3e2d1c0b9a8e7d6c5b4a3210fedc hello.txt
040000 tree 1a23c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1 src
項目 意味
オブジェクト種別 tree Treeオブジェクト
サイズ 96 本文部分のバイト数
ファイルモード 100644 , 040000 100644:通常ファイル
040000:ディレクトリ
ファイル名 .gitattributes ファイル名
blobID 8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b91 など blobオブジェクトへの参照用ID
treeID 1a23c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1 treeオブジェクトへの参照用treeID
blobオブジェクトの中身
blob 58

# Project
このプロジェクトのサンプルリポジトリです。
Gitオブジェクトの構造を説明するためのサンプルです。
項目 意味
オブジェクト種別 blob blobオブジェクト
サイズ 58 本文部分のバイト数
ファイルの中身 # Project
このプロジェクトのサンプルリポジトリです。
Gitオブジェクトの構造を説明するためのサンプルです。
ファイルの中身

先述のHEADから現在チェックアウト済みのコミットの全ファイル情報を取得する場合は以下の手順で取得します。

  1. commitID から commitオブジェクト を取得
  2. commitオブジェクト に記載されている treeID から treeオブジェクト を取得
  3. treeオブジェクト に記載されている各ファイルの blob ID から blobオブジェクト を取得

objects.png

ステージングエリア内の情報を確認したい場合は、先述の.git/indexに各ファイルの blob ID が記載されているため、直接 blobオブジェクト を参照できます。

■ packedオブジェクトについて

.git/objects には、到達可能な過去コミットの情報も全て管理されています。

到達可能な過去コミットとは

以下のような参照から辿ることのできるコミットを指しています。

参照元
ブランチ .git/refs/heads/main
タグ .git/refs/tags/v1.0.0
リモート追跡ブランチ .git/refs/remotes/origin/main
HEAD .git/HEAD
reflog .git/logs/HEAD, .git/logs/refs/heads/main
stash refs/stash

逆に到達不可能なコミットとは、以下のような場合を指します。

  • ブランチを削除した後、その履歴が他から参照されていない場合
  • reset --hard にて、ブランチの先端を戻した場合
  • rebase にて、古いコミット列が置き換わった場合
    など

到達不可能になった場合もすぐに削除されるわけではなく、reflog から辿ることができる間は削除されません。

つまり、到達可能な過去コミットであれば常に堆積し続けるということになります。
そんなことを続けていれば.git/objects内は大量のファイルであふれかえってしまいますね。
なので適切なタイミングで複数のlooseオブジェクトを統合・圧縮し、packedオブジェクトを生成することで容量の削減などを行っています。

差分だけ抽出して情報を削減(delta化)する場合もある

packfileを作成する際に似ているオブジェクト同士を探し、
 片方を   基準オブジェクト
 もう片方を 差分オブジェクト
として保存することがあります。

ただし、これは「コミット日時が古い順に並べて、古いファイルから順番に差分を作る」という単純な仕組みではありません。

Gitはオブジェクトの種類、サイズ、ファイル名・パス名などをもとに候補を並べ、
近い候補同士を比較して、差分圧縮した方が小さくなる場合にdelta化します。

ソースコードなどのテキストファイルであればこの恩恵を十分に受けることができますが、バイナリデータの場合は基本的にはこの恩恵は十分に発揮できません
なので、容量の大きいバイナリデータをGitで管理しようとしてしまうと.git/objectsの肥大化につながってしまいます。

この作業は git gc コマンドなどで明示的に実行することも可能ですが、一定以上情報が堆積した場合などにGit側が自動実行し、整理してくれるようになっています。

git gc コマンド実行前
.git/objects
├─01
├─04
├─05
├─06
├─07
├─0b
├─11
├─12
├─13
├─14
├─15
~省略~
├─info
└─pack
        pack-02b57f67f34247954badfdd69cba86b221008c65.idx
        pack-02b57f67f34247954badfdd69cba86b221008c65.pack
        pack-02b57f67f34247954badfdd69cba86b221008c65.rev
git gc コマンド実行後
.git/objects
├─info
│      commit-graph
│      packs
│      
└─pack
        pack-4afd2f323c41e8e3f4802cdeac6c39c4c8bd1ccb.idx
        pack-4afd2f323c41e8e3f4802cdeac6c39c4c8bd1ccb.pack
        pack-4afd2f323c41e8e3f4802cdeac6c39c4c8bd1ccb.rev

さいごに

今回まとめた内容だけでは「実用性」という観点では非常に低いと思っています。

ただし、Gitの各コマンドが内部でどのようなことをやっているのかについて、
ある程度ホワイトボックス的に理解できれば、メリット・デメリットを正しく判断し、
意図したとおりに使いこなせるのではないかと思っています。

今回の内容を踏まえたうえで、Gitの各コマンドが内部でどんなことをやっているのかについて深堀する記事を投稿出来たらと目論んでいるので…がんばりまーす

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?