.gitの中身を見てみる

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

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

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

# `.git` の中身を見てみる

まずは、Git管理するディレクトリを作成します。

```bash
$ mkdir git-study # ディレクトリ作成
$ cd git-study # 作成したディレクトリに移動
$ ls -la # ディレクトリの中身を隠しディレクトリも含めて表示
合計 0
drwxr-xr-x 1 user group    0 12月  1 15:36 .
drwxr-xr-x 1 user group 1292 12月  1 15:36 ..
$
```

上記はディレクトリを作成しただけなので、まだ何も入っていません。

```bash
$ git init # カレントディレクトリをGit管理下に置く
Initialized empty Git repository in /home/user/git-study/.git/
$ ls -la # 再度、ディレクトリの中身を表示する
合計 0
drwxr-xr-x 1 user group    8 12月  1 15:38 .
drwxr-xr-x 1 user group 1292 12月  1 15:36 ..
drwxr-xr-x 1 user group   98 12月  1 15:38 .git
$ 
```

カレントディレクトリ直下に `.git` ディレクトリが出来ました。
ではいよいよ、 `.git` ディレクトリの中を覗いてみます。

```bash
$ ls -lRa .git # `.git` ディレクトリの中身を再帰的に表示する
.git:
合計 12
drwxr-xr-x 1 user group  98 12月  1 15:38 .
drwxr-xr-x 1 user group   8 12月  1 15:38 ..
-rw-r--r-- 1 user group  21 12月  1 15:38 HEAD
drwxr-xr-x 1 user group   0 12月  1 15:38 branches
-rw-r--r-- 1 user group  92 12月  1 15:38 config
-rw-r--r-- 1 user group  73 12月  1 15:38 description
drwxr-xr-x 1 user group 506 12月  1 15:38 hooks
drwxr-xr-x 1 user group  14 12月  1 15:38 info
drwxr-xr-x 1 user group  16 12月  1 15:38 objects
drwxr-xr-x 1 user group  18 12月  1 15:38 refs

.git/branches:
合計 0
drwxr-xr-x 1 user group  0 12月  1 15:38 .
drwxr-xr-x 1 user group 98 12月  1 15:38 ..

.git/hooks:
合計 60
drwxr-xr-x 1 user group  506 12月  1 15:38 .
drwxr-xr-x 1 user group   98 12月  1 15:38 ..
-rwxr-xr-x 1 user group  478 12月  1 15:38 applypatch-msg.sample
-rwxr-xr-x 1 user group  896 12月  1 15:38 commit-msg.sample
-rwxr-xr-x 1 user group 4655 12月  1 15:38 fsmonitor-watchman.sample
-rwxr-xr-x 1 user group  189 12月  1 15:38 post-update.sample
-rwxr-xr-x 1 user group  424 12月  1 15:38 pre-applypatch.sample
-rwxr-xr-x 1 user group 1643 12月  1 15:38 pre-commit.sample
-rwxr-xr-x 1 user group  416 12月  1 15:38 pre-merge-commit.sample
-rwxr-xr-x 1 user group 1374 12月  1 15:38 pre-push.sample
-rwxr-xr-x 1 user group 4898 12月  1 15:38 pre-rebase.sample
-rwxr-xr-x 1 user group  544 12月  1 15:38 pre-receive.sample
-rwxr-xr-x 1 user group 1492 12月  1 15:38 prepare-commit-msg.sample
-rwxr-xr-x 1 user group 2783 12月  1 15:38 push-to-checkout.sample
-rwxr-xr-x 1 user group 3650 12月  1 15:38 update.sample

.git/info:
合計 4
drwxr-xr-x 1 user group  14 12月  1 15:38 .
drwxr-xr-x 1 user group  98 12月  1 15:38 ..
-rw-r--r-- 1 user group 240 12月  1 15:38 exclude

.git/objects:
合計 0
drwxr-xr-x 1 user group 16 12月  1 15:38 .
drwxr-xr-x 1 user group 98 12月  1 15:38 ..
drwxr-xr-x 1 user group  0 12月  1 15:38 info
drwxr-xr-x 1 user group  0 12月  1 15:38 pack

.git/objects/info:
合計 0
drwxr-xr-x 1 user group  0 12月  1 15:38 .
drwxr-xr-x 1 user group 16 12月  1 15:38 ..

.git/objects/pack:
合計 0
drwxr-xr-x 1 user group  0 12月  1 15:38 .
drwxr-xr-x 1 user group 16 12月  1 15:38 ..

.git/refs:
合計 0
drwxr-xr-x 1 user group 18 12月  1 15:38 .
drwxr-xr-x 1 user group 98 12月  1 15:38 ..
drwxr-xr-x 1 user group  0 12月  1 15:38 heads
drwxr-xr-x 1 user group  0 12月  1 15:38 tags

.git/refs/heads:
合計 0
drwxr-xr-x 1 user group  0 12月  1 15:38 .
drwxr-xr-x 1 user group 18 12月  1 15:38 ..

.git/refs/tags:
合計 0
drwxr-xr-x 1 user group  0 12月  1 15:38 .
drwxr-xr-x 1 user group 18 12月  1 15:38 ..
$ 
```

結構いろいろ入っていてログが長くなりました。
でも、空のディレクトリやフォルダも多いので、現時点で意味がありそうなファイルは下記くらいみたいです。

1. `.git/HEAD`
2. `.git/config`
3. `.git/description`
4. `.git/info/exclude`

（ `.git/hooks` ディレクトリ配下はサンプルっぽいので割愛します）

## 1. `.git/HEAD`

`.git/HEAD`はファイルなので、試しに  `cat` してみます。

```bash
$ ls -l .git/HEAD # 対象ファイルを確認する
-rw-r--r-- 1 user group 21 12月  1 15:38 .git/HEAD
$ cat .git/HEAD # 対象ファイルの中身を表示する
ref: refs/heads/main
$
```

ふつうに人間が読める感じの文字列が出てきました。
`refs/heads/main` がパスっぽいので、何があるか確認してみます。
(カレントディレクトリが `.git` の外なので、 `.git` を補ったパスで確認する)


```bash
$ ls -l .git/refs/heads/main # 対象ファイルを確認する
ls: '.git/refs/heads/main' にアクセスできません: そのようなファイルやディレクトリはありません
$ ls -l .git/refs/heads # ファイルがなかったので、試しに1つ上のディレクトリを確認する
合計 0
$ 
```

`refs/heads/main` は存在しないらしい。(`refs/head/` まではある)
もしかして、 `git init` しただけでコミットが1つもないからHEADもない、みたいな状況なのか？
試しに `git status`, `git log`をしてみます。

```bash
$ git status # ディレクトリのGitステータスを確認する
On branch main

No commits yet

nothing to commit (create/copy files and use "git add" to track)
$ git log # ディレクトリのGitログを確認する
fatal: your current branch 'main' does not have any commits yet
$
```

どちらもコミットがないって言ってますね。
試しにコミット作ったらどうなるか試したいけど、それは後日に回します。
（初期状態を全部確認しておきたいので）

## 2. `.git/config`

`.git/config` は名前からして設定ファイルっぽいです。
`cat` してみましょう。

```bash
$ ls -l .git/config # 対象ファイルを確認する
-rw-r--r-- 1 user group 92 12月  1 14:51 .git/config
$ cat .git/config # 対象ファイルの中身を表示する
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
$ 
```

これも人間が読める感じですね。
各設定値の意味を調査したのですが、難しくてよくわからなかったので公式ドキュメントだけ置いておきます。

https://git-scm.com/docs/git-config

## 3. `.git/description`

これも中身を見てみます。

```bash
$ ls -l .git/description # 対象ファイルを確認する
-rw-r--r-- 1 user group 73 12月  1 15:38 .git/description
$ cat .git/description # 対象ファイルの中身を表示する
Unnamed repository; edit this file 'description' to name the repository.
$
```

関連する公式ドキュメントは下記。

https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain

> The description file is used only by the GitWeb program, so don’t worry about it.
> （Google翻訳）説明ファイルは GitWeb プログラムによってのみ使用されるため、心配する必要はありません。

（心配する必要はないとは……？）

「GitWeb」で調べたら下記ドキュメントが出ました。

https://git-scm.com/book/en/v2/Git-on-the-Server-GitWeb.html

> If you want to check out what GitWeb would look like for your project, Git comes with a command to fire up a temporary instance if you have a lightweight web server on your system like lighttpd or webrick. On Linux machines, lighttpd is often installed, so you may be able to get it to run by typing git instaweb in your project directory.
> （Google翻訳）GitWeb がプロジェクトでどのように機能するかを確認したい場合は、lighttpd や webrick などの軽量 Web サーバーがシステムにある場合に一時的なインスタンスを起動するコマンドが Git に付属しています。Linux マシンでは、lighttpd がインストールされていることが多いため、プロジェクト ディレクトリで git instaweb と入力すると実行できる場合があります。

やってみる。

```bash
$ git instaweb # ドキュメントに従ってコマンドを実行してみる
lighttpd not found. Install lighttpd or use --httpd to specify another httpd daemon.
$ apt install lighttpd # lighttpdをインストール
#
# ログ省略
#
$ git instaweb # 再実行
```

Webページが表示されました。
「Description」欄に、 `.git/description` と同じような文字列が表示されています。

![Screenshot 2024-12-01 19.22.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319722/21e091c8-e9b8-68df-9bee-08b5efd11b79.png)

「Description」欄をクリックして詳細表示すると、全く同じ文字列が表示されました。

![Screenshot 2024-12-01 19.23.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319722/b0d023a1-8fa1-5c17-1dd3-88069d067ab5.png)

試しに `.git/description` を編集してみます。

```bash
$ cat .git/description # 変更前確認
Unnamed repository; edit this file 'description' to name the repository.
$ vi .git/description # viで編集
$ cat .git/description # 変更後確認
A project for learning Git.
$ git instaweb # 再起動
Instance already running. Restarting...
```

GitWeb上でも「Description」欄が更新されました。

![Screenshot 2024-12-01 19.26.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319722/e4e57ccc-de1d-6466-cbb2-2cd9be7429e3.png)

ここに表示されるだけの機能のようです。

## 4. `.git/info/exclude`

```bash
$ ls -l .git/info/exclude # 対象ファイルを確認する
-rw-r--r-- 1 user group 240 12月  1 15:38 .git/info/exclude
$ cat .git/info/exclude # 対象ファイルの中身を表示する
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
$ 
```

コメントアウトされているっぽい文字列が出てきました。
公式ドキュメントを確認してみます。

https://git-scm.com/book/ja/v2/Git%E3%81%A8%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E9%80%A3%E6%90%BA-Git-%E3%82%92%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E3%81%A8%E3%81%97%E3%81%A6%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B.html#_%E4%BD%BF%E3%81%84%E3%81%AF%E3%81%98%E3%82%81%E3%82%8B_2

> .git/info/exclude ファイルは .gitignore と同様の働きをしますが、コミットには含まれません。

これは、後日動作確認することにします。

---

本日はここまで！

# 参考書籍・参考資料

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