最初のgitの動作を図で理解する1

# はじめに

前回の`git`の挙動について、今回はその内容を図で確認していく。

https://qiita.com/rairaii/items/261071799ee3c1facd94


# 最初のgitコマンドを用意する

最初の`git`コマンドを[ビルド](https://qiita.com/rairaii/items/261071799ee3c1facd94#%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E3%83%93%E3%83%AB%E3%83%89%E3%81%99%E3%82%8B)し、`$HOME/bin-git にコピーして、コピーした場所へのPATHを通してあると仮定する。

```terminal:$HOME/bin-git
$ ls $HOME/bin-git
$ cat-file  commit-tree  init-db  read-tree  show-diff  update-cache  write-tree
$ export PATH=$PATH:$HOME/bin-git
$ which cat-file
/$HOME/bin-git/cat-file
```


# 確認する内容

下記のコマンド実行によるリポジト内部の変更を逐次確認することで`git`の動作を理解する。

```terminal:確認するコマンド
$ init-db                  # リポジトリの初期化
$ echo "Hello" > README.md # gitで管理するファイルを作成
$ cat README.md            # 　作成したファイルの内容を確認
Hello
$ update-cache README.md   # コミットするファイルをgitに登録
$ write-tree               # コミットするためにtreeオブジェクトを作成
5b884d166f3d56691ba080195ca0ceaed25f14b9
$ echo "1st commit" | commit-tree 5b884d166f3d56691ba080195ca0ceaed25f14b9 # コミット
Committing initial tree 5b884d166f3d56691ba080195ca0ceaed25f14b9
79df7b69d49cf4decaee4353d375af5390434041
$ echo "Hello, World" > README.md # ファイル内容を変更
$ show-diff                       # 変更内容を確認
README.md:  3c510aa6ed4c90af836505a9da8d9d2a0f36c5c9
--- /tmp/show_diff.fKo3Xz	2024-01-03 16:25:16.771067627 +0900
+++ README.md	2024-01-03 16:24:55.966972373 +0900
@@ -1 +1 @@
-Hello
+Hello, World
$ update-cache README.md          # コミットするファイルをgitに登録
$ write-tree                      # コミットするためにtreeオブジェクトを作成
056a16ec6554427cee5f2c087c4a3be4a6022e4b
$ echo "2nd commit" | commit-tree 056a16ec6554427cee5f2c087c4a3be4a6022e4b # コミット
Committing initial tree 056a16ec6554427cee5f2c087c4a3be4a6022e4b
ec74c2dcdcfbf5a576fc63ceece2179dc0a21d3f
```


# リポジトリの初期化
`git init`に相当する処理

```terminal
$ init-db
defaulting to private storage area
```

:::note info
`.dircache`ディレクトリがリポジトリ用のフォルダとして作成される
:::

`git`が管理するオブジェクトは`.dircache`フォルダの下の`objects`フォルダの下に配置される。多数のオブジェクトを効率よく管理するため、`00`から``ff`の256個のフォルダがさらに用意される。

```: リポジトリ構成
.dircache/
└── objects
    ├── 00
    ├── 01
    ...
    └── ff
```

# ファイルを登録する
`git add`に相当する処理を行う。

ワーキングディレクトリに`README.md`ファイルを作成し、そのファイルを`git`に登録する
```terminal:ファイルを作成
$ echo "Hello" > README.md
$ cat README.md
Hello
```

```terminal:ファイルを登録する
$ update-cache README.md
```
:::note info
指定したファイルを`blob`オブジェクトとしてファイルに保存して、そのファイルへの参照を`index`フィルに書き込む
:::

ファイルを登録した後のリポジトリの構成
- [add] objects/3c/510aa6ed4c90af836505a9da8d9d2a0f36c5c9
- [add] index

```:リポジトリ構成
.dircache/
├── index
└── objects
    ├── 00
    ...
    ├── 3c
    │   └── 510aa6ed4c90af836505a9da8d9d2a0f36c5c9
    ...
    └── ff
```

## 登録された`README.md`ファイルの管理
`objects/3c/510aa6ed4c90af836505a9da8d9d2a0f36c5c9`ファイルで管理される。
- ファイルはzlibで圧縮され`blobオブジェクト`として管理される
- SHA1ハッシュでの管理方法
    - `3c`:ディレクトリ名
    - `510aa6ed4c90af836505a9da8d9d2a0f36c5c9`:ファイル名
    
`blobオブジェクト`は`index`ファイルで管理される
- `blobオブジェクト`として保存された`README.md`ファイルへの参照(SHA1ハッシュ)を`index`に保存する
- 登録された`README.md`ファイルにアクセスしたい場合には`3c`フォルダの`51...c9`ファイルを確認すれば良い

![スクリーンショット 2024-01-03 16.20.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/9de5f006-abe5-d88a-e764-3d42bd1b81c8.png)


# コミットする
`git commit`に相当する処理を行う

コミットは`treeオブジェクト`を対象として行う。`tree`オブジェクトは1つ以上の`blob`オブジェクトへの参照を持つオブジェクトである。

```terminal: treeオブジェクトを作成してcommit
$ write-tree
5b884d166f3d56691ba080195ca0ceaed25f14b9
$ echo "1st commit" | commit-tree 5b884d166f3d56691ba080195ca0ceaed25f14b9
Committing initial tree 5b884d166f3d56691ba080195ca0ceaed25f14b9
79df7b69d49cf4decaee4353d375af5390434041
```

:::note info
`treeオブジェクト`を作成し、その`tree`オブジェクトを参照する`commitオブジェクト`を作成する。「コミットする」とは、`commitオブジェクト`を作成することであり、コミットの内容は`commitオブジェクト`が参照する`treeオブジェクト`が参照する`blobオブジェクト`一覧である。
:::

ファイルをコミットした後のリポジトリの構成
- [add] objects/5b/884d166f3d56691ba080195ca0ceaed25f14b9
- [add] objects/79/df7b69d49cf4decaee4353d375af5390434041

```:ディレクトリ構成
.dircache/
├── index
└── objects
    ├── 00
    ...
    ├── 3c
    │   └── 510aa6ed4c90af836505a9da8d9d2a0f36c5c9
    ...
    ├── 5b
    │   └── 884d166f3d56691ba080195ca0ceaed25f14b9
    ...
    ├── 79
    │   └── df7b69d49cf4decaee4353d375af5390434041
    ...
    └── ff
```


![スクリーンショット 2024-01-03 16.19.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/baa327a7-7ead-1832-daae-efc16218056b.png)


# ファイル変更

ワーキングディレクトリの`README.md`ファイルを変更する。

```terminal
$ echo "Hello, World" > README.md
```


# 変更点の確認
`git diff`に相当する処理を行う
登録されたファイルとワーキングディレクトリのファイルとの差分を表示する。

```terminal
$ show-diff
README.md:  3c510aa6ed4c90af836505a9da8d9d2a0f36c5c9
--- /tmp/show_diff.fKo3Xz	2024-01-03 16:25:16.771067627 +0900
+++ README.md	2024-01-03 16:24:55.966972373 +0900
@@ -1 +1 @@
-Hello
+Hello, World
```

:::note info
`index`ファイルに登録されたファイルとワーキングディレクトリのファイルの差分を`diff`コマンドを呼び出して作成して出力する。
:::


# 変更をコミット

`README.md`ファイルの修正をコミットする。
- コミットするファイルを`update-cache`コマンドで登録
- コミットに必要な`treeオブジェクト`を`write-tree`で作成
- コミット対象の`tree`オブジェクトをSHA1ハッシュで指定して`commitオブジェクト`を作成する

```terminal: 修正したコードを登録
$ update-cache README.md
$ write-tree
056a16ec6554427cee5f2c087c4a3be4a6022e4b
$ echo "2nd commit" | commit-tree 056a16ec6554427cee5f2c087c4a3be4a6022e4b
Committing initial tree 056a16ec6554427cee5f2c087c4a3be4a6022e4b
ec74c2dcdcfbf5a576fc63ceece2179dc0a21d3f
```

```:ディレクトリ構成
.dircache/
├── index
└── objects
    ├── 00
    ..
    ├── 05
    │   └── 6a16ec6554427cee5f2c087c4a3be4a6022e4b : 2nd tree オブジェクト
    ..
    ├── 3c
    │   └── 510aa6ed4c90af836505a9da8d9d2a0f36c5c9 : 最初の README.md
    ..
    ├── 5b
    │   └── 884d166f3d56691ba080195ca0ceaed25f14b9 : 1st tree オブジェクト
    ├── 5c
    ├── 5d
    ├── 5e
    ├── 5f
    │   └── 60b55715af0273fd592428a179c59299a0987f : 修正した README.md
    ├── 60
    ..
    ├── 79
    │   └── df7b69d49cf4decaee4353d375af5390434041 : 1st commit オブジェクト
    ..
    ├── ec
    │   └── 74c2dcdcfbf5a576fc63ceece2179dc0a21d3f : 2nd commit オブジェクト
    ├── ed
    └── ff

```

:::note info
修正したREADME.mdファイルの`blobオブジェクト`を新規に作成し、そのファイルへの参照を`index`ファイルに保存する。`index`ファイルは`update-cache`を呼び出す毎に更新されるため、前回登録したファイルへの参照は消える。
:::


![スクリーンショット 2024-01-03 17.10.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/f037a292-636d-506f-0323-08989f396580.png)


# 次回

次回は複数のファイルやディレクトリを対象にコミットした場合や、コミットからのリストアについて動作を確認していく。

https://qiita.com/rairaii/items/45e1b19d431646fcd1d2