.git の中身を見てみる2(git add) つづき

### 編集履歴

- 2024/12/22
  - `git cat-file -t` コマンドの実行を追記(後続記事の説明のため)

---

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

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

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

# .git の中身を見てみる2(git add) つづき

下記の続きです。

https://qiita.com/lizhi05853/items/db538778e79488072453

「a.txt」というファイルを作成、 `git add` して 、前後の `.git` の中身を比較してみます。
(昨日の記事は `-r` オプションつけ忘れてました、すみません。おいおい直します)

```bash
$ diff -r .git ../git-study-before-add/.git # 
.git のみに存在: index
.git/objects のみに存在: e6
$
```

差分が2件出てきました。
内容を確認します。

## 差分1(`.git/index`)

```bash
$ ls -l .git/index
-rw-r--r-- 1 user group 104 12月  2 22:33 .git/index
$ cat .git/index
DIRCgMf
       `gMf
           `5%EI⛲CK)wZSa.txtsT}ss:YE$ 
```

`.git/index` というファイルが作成されていましたが、中身はバイナリでした。
このままだとよくわからないので、 `git ls-files --stage` コマンドを使います。
このコマンドを使うと、ステージングされた(インデックスに追加された)差分情報を確認することができます。

https://git-scm.com/docs/git-ls-files

```bash
$ git ls-files --stage
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0       a.txt
$ 
```

スペース区切りで4つの情報が表示されています。
公式ドキュメントによると、左側から「[mode] [object] [stage] [file]」とのことです。

modeとstageは調べてもよくわからなかったのですが、objectは対象ファイルの中身から作成したSHA-1ハッシュ値らしいです。

https://git-scm.com/docs/gittutorial-2#_the_git_object_database

## 差分2(`.git/objects/e6`)

もう一つの差分を確認します。

```bash
$ ls -l .git/objects/e6
合計 4
-r--r--r-- 1 user group 15 12月  2 22:33 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
$ cat .git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
xKOR0`  $ 
```

`e6` はディレクトリで、その中に `9de29bb2d1d6434b8b29ae775ad8c2e48c5391` というファイルがありました。
このディレクトリ名とファイル名をくっつけると、 `git ls-files --stage` コマンドで出てきたハッシュ値と一致します。

これも中身はバイナリですが、 `git cat-file` を使うと内容を確認できます。
`-t` オプションで種類(タイプ)が、 `-p` オプションでファイルの中身を見られます。


```bash
$ git cat-file -t e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
blob
$ git cat-file -p e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
$ 
```

中身は空でした。
そもそも「a.txt」の中身が空なので、オブジェクトファイルの中身も空だったわけです。

## ファイルの中身に値を入れてみる

では、「a.txt」に値があったらどうなるか試します。

まずは、ディレクトリ全体をコピーします。

```bash
$ cd ..
$ ls -ld git-study*
drwxr-xr-x 1 c05853yy c05853yy 18 12月  2 22:13 git-study
drwxr-xr-x 1 c05853yy c05853yy 18 12月  2 22:13 git-study-before-add
drwxr-xr-x 1 c05853yy c05853yy  8 12月  1 15:38 git-study-before-create-file
$ cp -pr git-study git-study-before-write
$ ls -ld git-study*
drwxr-xr-x 1 c05853yy c05853yy 18 12月  2 22:13 git-study
drwxr-xr-x 1 c05853yy c05853yy 18 12月  2 22:13 git-study-before-add
drwxr-xr-x 1 c05853yy c05853yy  8 12月  1 15:38 git-study-before-create-file
drwxr-xr-x 1 c05853yy c05853yy 18 12月  2 22:13 git-study-before-write
$ 
```

「a.txt」ファイルを更新して、インデックスに追加します。

```bash
$ cd git-study
$ cat a.txt 
$ echo "test" > a.txt 
$ cat a.txt 
test
$ git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   a.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   a.txt

$ git add a.txt 
$ git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   a.txt

$ 
```

作業前後で `.git` ディレクトリを比較します。

```bash
$ diff -r .git ../git-study-before-write/.git
バイナリーファイル .git/index と../git-study-before-write/.git/index は異なります
.git/objects のみに存在: 9d
$ 
```

`.git/index` ファイルが更新されて、新しいオブジェクトファイルも出来ているみたいです。

```
$ git ls-files --stage
100644 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 0       a.txt
$ git cat-file -t 9daeafb9864cf43055ae93beb0afd6c7d144bfa4
blob
$ git cat-file -p 9daeafb9864cf43055ae93beb0afd6c7d144bfa4
test
$ 
```

ちなみに、最初にできていた空のオブジェクトファイルはどうなったのか確認したら、元のまま置いてありました。
消されるわけではないようです。

```bash
$ ls -l .git/objects/e6
合計 4
-r--r--r-- 1 user group 15 12月  2 22:33 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
$ 
```

今日はここまで。

# 参考書籍・参考資料

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