自分用メモ。
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/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