Git を1からやり直す(マージ編)

Gitを1からやり直す(目次)

マージ

mergeとは、他のブランチの変更を取り込むこと。

コマンド 動作など
git merge ブランチ名 マージする。可能な場合は早送りマージとなる
git merge --no-ff ブランチ名 --no-ff:早送りマージ(ff)をさせないオプション
git merge --ff-only ブランチ名 早送りマージをする。早送りができなければエラー
git merge --abort コンフリクト発生時、merge を中止して元に戻す
git merge --continue コンフリクト発生時、コンフリクト解消 → add → continue で merge を続ける

(例)masterブランチにいる状態で、$ git merge developを実行すると、developブランチの内容が masterブランチに取り込まれる。

3方向マージと早送りマージ

Gitのマージには3方向マージ(Non Fast-Forword)と早送りマージ(Fast-Forword)の2種類がある(GitHubではなくGitの話!)。

3方向マージは、2つのブランチが分かれたコミット、変更を取り込むブランチ、取り込まれるブランチの3者でマージが行われ、マージコミットが作られる。コミットが作られるので、コミットメッセージの入力画面が出る。

一方早送りマージは、取り込む側のブランチの先端を、取り込まれる側のブランチの先端に動かすだけなので、マージコミットは作られない。よってコミットメッセージの入力画面は出ない。

以下で、masterブランチに developブランチを取り込む例をそれぞれ見てみる。

$ git checkout master  # master ブランチに移動
$ git merge develop  # develop ブランチを取り込む

3方向マージ(Non Fast-Forword)の場合

# マージ前
master  A - B - C - D - E (masterの先端)
                 \
develop           L - M - N (developの先端)

# 3方向マージ後(マージコミット X が作られる)
master  A - B - C - D - E - X (masterの先端)
                 \         /
develop           L - M - N (developの先端)

このように、C・E・N を元にマージコミット X が作られる。

それぞれのブランチで開発が進んでいるので、コンフリクト(衝突)が起こる可能性がある。コンフリクトとは、それぞれが同じ箇所を変更していたためGit側で自動マージができないこと。コンフリクトが起きたときは、直接ファイルを編集してコンフリクト解消後、add → git merge --continue(またはcommit)する。

早送りマージ(Fast-Forword)の場合

# マージ前
master   A - B - C (masterの先端) 
                  \
develop            L - M - N (developの先端)

# 早送りマージ後(マージコミットは作られない)
master  
         A - B - C - L - M - N (masterの先端、developの先端)
develop          

はじめ masterブランチの先端(とHEAD)は C にあったが、マージによって先端(とHEAD)が N に移動する。この後 master ブランチでコミットすると、N の先に master が伸びていく。さらに develop ブランチでコミットすると、N から枝分かれして伸びていくことになる。

早送りマージは、枝分かれ後に取り込む側のブランチが伸びていないときだけ行うことができる。上図では、枝分かれするコミット C 以降、master ブランチは伸びていないので早送りマージが可能となる。コンフリクトが起こることはない。

ただ、早送りマージをするとマージしたという記録が残らないため、早送りマージはするべきでないという議論もある。

Git - ブランチとマージの基本


(参考資料)わかる Git