Gitのマージって2種類あったのか
Fast-forwardとNon-fast-forwardの2種類です。
まずはGitのブランチとは何ものだったのかについて
Gitのリビジョンはひとつごとに
- リビジョンを表すハッシュ
- 前のリビジョン
- 変更差分
の3つと、コミットを作成した人と適用した人の情報を持っています。
ブランチ名はある一連のコミットにおける最新版の別名です。
①ー②ー③ー④ー⑤←master
の「master」がそうです。
ちなみにcheckoutするときはブランチ名を指定すると思いますが、ブランチ名は一連のコミットの最新版を指す別名なので、あるリビジョンのハッシュをcheckoutするという芸当もできます。
Gitではひとつのリビジョンに複数のブランチ名をつけることができます。これが「git baranch 名前」というコマンドです。この段階ではまだ枝分かれしておらず、どちらかのブランチをチェックアウトしてコミットした段階で初めて枝分かれします。
Fast-forward(早送り)
マージしようとしているブランチの先祖にマージさせたいブランチがあるとき、GitはFast-forwardマージをやります。
図解するとこんなかんじです。
①ー②←master └─③ー④ー⑤←topic
このときmergeブランチにtopicブランチをマージするとFast-forwardで解決されて、こうなります。
①ー②ー③ー④ー⑤←master←topic
masterにtopicで新たにできたコミットを足しあわせても、確実に衝突することなくマージできますね。というわけで、特別な計算をすることなく、「ブランチの指しているリビジョンを書き換えるだけでいいじゃん」という作戦をとるわけです。
Non-fast-forward(それ以外)
たとえばこんなときはFast-forwardでは解決できません。
①ー②ーー④←master └─③ー⑤ー⑥←topic
今回は簡単に足し合わせるだけでは衝突するかもしれないので、ちゃんとマージしてその結果のリビジョンを作成します。これがNon-fast-forwardマージです。
結果は以下の通り。
①ー②ーー④ーーーー⑦←master └─③ー⑤ー⑥ー-┘ ↑topic
これを繰り返すとこうなります。
ちなみに去年はこういうコミットグラフを作ると確実にておくれました*1が、今は大丈夫になりました。
*1:masterブランチのみの一本道でもなぜかローカルとリモートで競合してプッシュできなかったことがあった