Gitのブランチは「付箋」だと思えばいい
Gitのブランチと聞くと、「コードのコピーが丸ごともう1セットできる」イメージを持ちがちです。でも実態はずっと軽くて、ブランチとはコミットの鎖に貼られた1枚の「付箋」にすぎません。コミットするとその付箋がぺたっと1つ先に貼り直される — それだけです。
下の図1は実際に操作できるコミットグラフです。コミットして、ブランチを作って、マージまで自分の手でやってみてください。
コミットは「鎖」、ブランチは「付箋」
図1で見たとおり、歴史の本体は親を指し示しながらつながっていくコミットの鎖です。一度作られたコミットは変わりません。ブランチはその鎖のどこか1点を指す付箋で、コミットのたびに1つ先へ貼り直されます。だからブランチを100本作ってもリポジトリはほとんど重くなりませんし、ブランチの削除も「付箋を剥がすだけ」なので一瞬です。
そしてHEADは「いまどの付箋の上で作業しているか」を指すただ1つの目印です。git switch はファイルをコピーしているのではなく、このHEADを別の付箋に付け替えているだけです。
マージには2種類ある
図1でマージを試すと、状況によって起きることが変わります。枝分かれのあとmainが1歩も進んでいなければ、合流点を作る必要はなく、mainの付箋をfeatureの先頭まで滑らせるだけで済みます。これがfast-forwardです。一方、mainも先に進んでいた(歴史が分岐していた)場合は、親を2つ持つマージコミットを新しく作って2本の歴史を合流させます。
リベースは3つ目の選択肢で、featureのコミットたちをmainの先頭の続きとして作り直す(コピーする)操作です。図1では元のコミットが薄くなり、同じ内容の新しいコミットが付け替わるのが見えます。歴史が一直線になるので、そのあとのマージはfast-forwardで済みます。
- HEAD
- 「いまここで作業中」を示す目印。ふだんはどれか1つのブランチ(付箋)を指す。
- fast-forward
- 合流点を作らず、付箋を先へ滑らせるだけで完了するマージ。
- マージコミット
- 親を2つ持つ特別なコミット。分岐した2本の歴史をここで束ねる。
- リベース
- 枝のコミットを別の場所の続きとして作り直すこと。元のコミットは残るが付箋から外れる。
まとめ
ブランチを「重いコピー」だと思うと作るのをためらいますが、実態は付箋1枚です。気軽に貼って、試して、ダメなら剥がせばいい。コミットの鎖・付箋(ブランチ)・現在地(HEAD)の3つが見えていれば、マージもリベースも「付箋とグラフがどう動くか」の話にすぎません。怖くなったら、この図に戻ってきてください。