Stage 2・中級編 ー Lesson 2-2
git merge とは? ブランチを統合しよう
git merge で別ブランチのコミットを取り込み、変更を1本に統合する
💡 たとえるなら
ゲームのセーブには本来ない操作だが、別ルートで進めたセーブデータを本編のセーブに合流させるイメージ
前のレッスンで feature ブランチを作りました。実験がうまくいったら、いよいよその変更を main に取り込みます。これが マージ(merge) です。
マージって何?
「あるブランチで作ったコミットを、別のブランチに合流させる」操作です。コマンドはシンプル:
ポイントは 「乗り換えてから merge する」 こと。git merge X は「今いるブランチに X を取り込む」という意味なので、main に取り込みたいなら main にいる状態で実行します。
2種類のマージ:fast-forward と 3-way
git merge には2つの動き方があります。状況によって自動で切り替わるので、概念を押さえておけばOK。
① fast-forward マージ(早送り)
main が feature を作ったあと 何も進んでいない ときは、ただ main の HEAD を feature の先端まで「早送り」するだけ。新しいマージコミットは作られません。
「main は止まったまま、feature だけ進んだ」状況で起きます。
② 3-way マージ(合流)
main も feature も両方コミットが進んでいるときは、両者を統合した マージコミット が新しく作られます。
3-wayマージは「2つのブランチが分岐してそれぞれ進んだ後、合流させた歴史」を残します。後から git log --graph で見ると枝分かれが視覚的にわかります。
Git は 3つのコミットを見比べてマージ結果を作ります:① 共通の祖先(分岐前のコミット)、② 自分の側の先端(main)、③ 相手の側の先端(feature)。この「3点を比較する」方式なので 3-way(3方向)マージと呼ばれます。
やってみよう ①:fast-forward マージ
まずは fast-forward から。my_project で:
main が止まったままだったので fast-forward が起きました。「Fast-forward」と表示されていますね。マージコミットは作られていません。
やってみよう ②:3-way マージ
次は main も進んでいる状態 を作って、3-way マージを起こしてみます。さっきのマージで使った feature ブランチは消しておいて:
今度は 「Merge made by the ‘ort’ strategy」 と出て、マージコミットが作られた ことがわかります(“ort” は Git の3-wayマージのデフォルト戦略名)。
3-wayマージするとエディタが開いて
Merge branch 'feature' という既定メッセージが表示されます。そのまま保存して閉じればOK。
ちなみに今回は 違うファイル を別々に変更したのでぶつかりませんでしたが、同じファイルの同じ行 を別々に変更していると衝突します。詳しい対処は次のレッスン 「コンフリクトを解決する」 で扱います。
マージの結果を確認する
git log --oneline --graph --all で履歴を見ると、2つのマージの違いが一目でわかります。
fast-forward マージの結果
1本道 で枝分かれがありません。マージコミットも作られていないので、見た目は「最初から1本だった」かのように見えます。HEAD -> main, feature と並んでいるのは、main と feature が同じコミットを指しているという意味(fast-forward の特徴)。
3-way マージの結果
枝分かれと合流 が線で表現されています。読み方:
- 一番上
Merge branch 'feature'= マージコミット(さっきの 3-way で生まれたやつ) |\= ここから2つに枝分かれしている| *= 右側の枝(feature)のコミットfeature.txt を追加* |= 左側の枝(main)のコミットmain で memo を更新|/= ここで合流していた(共通の祖先e4f5g6h)
比較まとめ
| fast-forward | 3-way | |
|---|---|---|
| マージコミット | できない | できる |
| 履歴の見た目 | 一本道 | 枝分かれが残る |
| 起きる条件 | 取り込み先が止まっていた | 両方が進んでいた |
git merge --no-ff feature と --no-ff を付けると、fast-forward 可能でも必ずマージコミットを作ります。「どの feature を統合したか」を履歴に残したいチームでよく使われます。詳しくは Stage 3-6 で扱います。
マージしたあとの feature ブランチ
main に取り込んだら、もう feature ブランチは不要なことが多いです。前レッスンの git branch -d で削除しましょう:
「マージしてから削除」が定番フロー。
マージで衝突が起きたら?
両ブランチが 同じファイルの同じ行 を別々に書き換えていると、Gitは自動マージできずに止まります。詳しい解決方法は次のレッスン 「コンフリクトを解決する」 で扱います。
このレッスンのまとめ
git merge で別ブランチを取り込めるgit log --graph --all で履歴の構造を確認できるgit branch -d で削除する✏️ 理解度チェック
各問題、選んだ瞬間に正解と解説が表示されます。気軽に試してください。
- Q1. feature ブランチを main に取り込みたい。正しい操作は?
- Q2. fast-forward マージとはどんなマージ?
- Q3. 両ブランチが分岐している場合の merge では何が作られる?