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