.gitファイルをいろいろ調べてみる

自分用メモ。
Gitのブランチってどう管理されてるんだろ、って疑問に思ったので調べてみる。
ここでの`cd`コマンドは今いるディレクトリの説明を省略して打っているコマンドです。

# 【実験】ブランチは.gitファイルでどのように管理されているのか
`git init`で生成される`.git`ファイルについて見てみます。

## 1. masterブランチを作る

```
$ cd .git
$ ls                                                                 
COMMIT_EDITMSG   config           index            objects
HEAD             description      info             refs
branches         hooks            logs             sourcetreeconfig
```

このなかで、ブランチは`refs`の中で管理されているようです。
(他のファイルはなんだろう。調査する。)

```
$ cd refs/heads
$ ls
（何も表示されない。）
```
`git init`でgitを有効にしたあと、何かしらファイルをコミットしないと`master`ブランチは生成され（てるけど、ディレクトリ上は見れ）ないようです。なので、適当なファイルを作ってみる。

```
touch sample.txt
```
このファイルをコミットすると、`ls`コマンドで`master`が現れます。

```
$ cd refs/heads
$ ls
master
```

## 2. featureブランチを作る

ここで新しくブランチ`feature`をつくって見ます。

```
$ git branch feature
$ cd refs/heads
master feature
```

これで`feature`ブランチができました。これは**ディレクトリではなくファイル**ですね。

## 3. feature/hogehogeを作ってみる。
では次に`feature/hogehoge`を作ってみましょう。

```
$ git branch feature/hogehoge
fatal: cannot lock ref 'refs/heads/feature/hogehoge': 'refs/heads/feature' exists; cannot create 'refs/heads/feature/hogehoge'
```

ブランチ`feature`の下にファイルを追加しようとしているためか怒られました。

## 4. feature2/hogehogeを作ってみる
それでは、（少しわかりにくいですが）`feature2/hogehoge`を作ってみましょう。

```
$ git branch feature2/hogehoge
$ ls (/headsディレクトリで。)
feature  feature2  master
```
新しく`feature2`が追加されましたね！ここで注意するのは、`feature2`はファイルではなくディレクトリということです。では`cd`コマンドが使えるはずなので、潜ってみましょう

```
$ cd feature2
$ ls
hogehoge
```

`hogehoge`ファイルが追加されているのがわかります。

## 5. feature2/fugafugaを追加する

```
$ git branch feature2/fugafuga
$ cd feature2
$ ls
hogehoge  fugafuga
```
ブランチ`feature/fugafuga`が追加されました！

## 6. feature2ディレクトリは削除できる？
ディレクトリ管理なら`feature2/`ディレクトリは削除できるのではないかと思い、実験

```
$ git branch -d feature2
error: branch 'feature2' not found.
```
ふむ。ブランチを消す操作は、ディレクトリに対する操作ではないのね。

なら、これは？

```
$ git branch -D feature2
error: branch 'feature2' not found.
```
同じ結果になりました。

## 7. featureブランチのファイルをコピーして名前を変えたら？

```
$ cd refs/heads
$ cp feature feature3
$ ls 
feature  feature2 feature3 master
```

ここでブランチを確認してみると、

```
$ git branch 
  feature  
  feature2 
  feature3 
* master
```

新しくブランチができました。（でもこの`feature3`ってちゃんと使えるのかな）

# 【調査】 refs / objects その他
[これ](https://git-scm.com/book/ja/v1/Git%E3%81%AE%E5%86%85%E5%81%B4-%E3%83%91%E3%83%83%E3%82%AF%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB)によると、gitで最初に格納されるフォーマットは`loose object format`というらしい。`git commit`していくとブランチの情報が`refs/heads`内に格納されてて、各コミットの情報が`.git/objects`のなかに格納されていく。ブランチの情報は、最新のコミットのハッシュ値だけをもつみたい。

やってみる。

新しくコミットしたあとに、`refs/heads/master`を確認

```
$ cd refs/heads
$ cat master
5356090e768f.........d137a7b0eff780
```

また、`objects/`内をみると、

``` 
$ cd objects/
$ ls
35   53   79   c0   dd   f1   info pack
```

どうもこれらは、各コミットのハッシュ値の先頭2文字らしい。今回は`53`なので、

```
$ cd 53
$ ls
56090e768f.........d137a7b0eff780
```

じゃあ、新しくコミットを追加したらどうなる？ 新しくコミット追加したあとに、`refs/heads/master`を確認

```
$ cd refs/heads
$ cat master
a58c0fe2b..........9310d6c2170a0f
```

```
$ cd objects/a5
$ ls 
8c0fe2b..........9310d6c2170a0f
```

## `git gc`コマンドがあるらしい
gc (garbage collection) をすると、先程`refs/`や`objects/`にあったコミットファイルを、パックしてくれる。

```
git gc 実行前
$ cd objects/
$ ls
35   53   79   a5   c0   dd   ed   f1   f7   info pack

git gc 実行後
$ cd objects/
$ ls
info pack
```
ただし、
> Git は時々 "auto gc" と呼ばれるコマンドを自動的に実行します。
>
> 繰り返しますが、これは通常は何も行いません。約 7,000個もの緩いオブジェクトがあるか、または50以上のパックファイルがないと、Gitは実際に gc コマンドを開始しません。
>
https://git-scm.com/book/ja/v1/Git%E3%81%AE%E5%86%85%E5%81%B4-%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%86%E3%83%8A%E3%83%B3%E3%82%B9%E3%81%A8%E3%83%87%E3%83%BC%E3%82%BF%E3%83%AA%E3%82%AB%E3%83%90%E3%83%AA から引用

のようにあまり自分で積極的に行うものではないのか。

# 参考
- https://git-scm.com/docs/git-pack-refs
- https://stackoverflow.com/questions/5709687/what-are-the-loose-objects-that-the-git-gui-refers-to
- https://git-scm.com/book/ja/v1/Git%E3%81%AE%E5%86%85%E5%81%B4-%E3%83%91%E3%83%83%E3%82%AF%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB
- https://git-scm.com/book/ja/v1/Git%E3%81%AE%E5%86%85%E5%81%B4-%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%86%E3%83%8A%E3%83%B3%E3%82%B9%E3%81%A8%E3%83%87%E3%83%BC%E3%82%BF%E3%83%AA%E3%82%AB%E3%83%90%E3%83%AA