Git
branch

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

More than 1 year has passed since last update.

自分用メモ。
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 その他

これによると、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 から引用

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

参考