.gitの中身を見てみる4(オブジェクト)

Gitでバージョン管理されたプロジェクトを扱うと、必ず `.git` というディレクトリがあります。

このディレクトリを使ってGitがバージョン管理をしているらしい、ということはなんとなく知っています。でも、具体的になにが入っていて、どう管理されているんだろう？

このアドベントカレンダーは、そんな疑問からGitを深堀りしていきます。

# オブジェクト

[こちら](https://qiita.com/lizhi05853/items/ff68bc6376bde1c25d7c#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%B8%AD%E8%BA%AB%E3%81%AB%E5%80%A4%E3%82%92%E5%85%A5%E3%82%8C%E3%81%A6%E3%81%BF%E3%82%8B)と[こちら](https://qiita.com/lizhi05853/items/75c4e9b93a428da11bc3#%E5%B7%AE%E5%88%8645gitobjects58-gitobjectse4)の記事より、 `.git/objects/` ディレクトリの中にはバイナリファイルが入っていることがわかりました。

また、 `git cat-file` コマンドを利用することで、バイナリファイルのタイプと中身を見られることもご紹介しました。

(再掲)

``` bash
$ git cat-file -t 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 # タイプ
blob
$ git cat-file -p 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 # 中身
test
$ 

$ git cat-file -t 58c608a3fa830548019591fc45f307554ca9a57f # タイプ
tree
$ git cat-file -p 58c608a3fa830548019591fc45f307554ca9a57f # 中身
100644 blob 9daeafb9864cf43055ae93beb0afd6c7d144bfa4    a.txt
$

$ git cat-file -t e452a0a52250236a24d1f63dd7e7fbb84d6e55c5 # タイプ
commit
$ git cat-file -p e452a0a52250236a24d1f63dd7e7fbb84d6e55c5 # 中身
tree 58c608a3fa830548019591fc45f307554ca9a57f
author user <user@machine> 1733321663 +0900
committer user <user@machine> 1733321663 +0900

commit test
$ 
```

以下では、これら3つのオブジェクトのタイプについて確認していきます。

## (1) blobタイプ

blobタイプのオブジェクトは `git add` コマンドを実行すると作成されました。

中にはファイルの中身だけが入っています。
ファイルの中身を書き換えたら、元のblobオブジェクトはそのまま残って、新しいblobオブジェクトが作成されます。

https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88.html#r_objects:~:text=%E3%81%93%E3%81%AE%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%BF%E3%82%A4%E3%83%97%E3%81%AF%E3%83%96%E3%83%AD%E3%83%96%EF%BC%88blob%EF%BC%89%E3%81%A8%E5%91%BC%E3%81%B0%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82

## (2) treeタイプ

treeタイプのオブジェクトは `git commit` コマンドを実行するとされました。

その中には以下の4つが記載されます。

1. モード
1. 「object」※3のオブジェクトタイプ
1. コミットしたファイルを表すobjectディレクトリのハッシュ値
1. ファイル名

なお、もしコミットしたファイルがディレクトリの中に入っていれば、以下のようになります。

1. モード
1. 「tree」※3のオブジェクトのタイプ
1. ディレクトリを表すtreeオブジェクトのハッシュ値
1. ディレクトリ名

1のモードは、「UNIXモードから取り入れた概念ですが、それほどの柔軟性はありません。」とのことです。(公式ドキュメントより)

blobファイルに対しては下記3つのモードがあるそうです。(ディレクトリについては詳しい説明がありませんでした)

- 100644：通常のファイル
- 100755：実行可能ファイル
- 120000：シンボリックリンク

https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88.html#r_objects:~:text=t%201f7a7a472abf3dd9643fd615f6da379c4acb3e3a%0Ablob-,%E3%83%84%E3%83%AA%E3%83%BC%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88,-%E6%AC%A1%E3%81%AE%E3%82%BF%E3%82%A4%E3%83%97

## (3) commitタイプ

commitのオブジェクトも、treeオブジェクトと同様に `git commit` コマンドを実行するとされました。

中にはコミットに関するメタデータが入っています。
具体的には下記の5つの情報です。

- treeオブジェクトのハッシュ値(コミットが作成された時点のスナップショット)
- 作者
- コミッター
- 空行
- コミットメッセージ

commitオブジェクトのハッシュ値は `git log` コマンドで確認できます。

```bash
$ git log
commit e452a0a52250236a24d1f63dd7e7fbb84d6e55c5 (HEAD -> main)
Author: user <user@machine>
Date:   Wed Dec 4 23:14:23 2024 +0900

    commit test
$ 
```

https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88.html#r_objects:~:text=%E5%86%85%E5%AE%B9%E3%81%AE%E6%A7%8B%E6%88%90-,%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88,-%E8%BF%BD%E8%B7%A1%E3%81%97%E3%81%9F%E3%81%84

以上をまとめると、Gitは管理対象のファイルを下記の3つに分けて管理していることがわかります。

1. ファイルの中身(blobオブジェクト)
1. コミット時点のスナップショット(treeオブジェクト)
1. コミットのメタデータ(commitオブジェクト)

そして、この3つの情報は、 `git log` コマンド -> commitオブジェクト -> treeオブジェクト -> blobオブジェクトと辿っていくことが出来ます。

# 参考書籍・参考資料

- エンジニアのためのGitの教科書［上級編］ Git内部の仕組みを理解する
    - https://amzn.asia/d/2PJeklb
- git 公式ドキュメント
    - https://git-scm.com/book/ja/v2