01 / 11
「安全に試したい、でも本番を壊したくない」
いま動いているコードに大きな機能追加や改修を入れたい。でも失敗したときにすぐ元の安全な状態へ戻せるようにしておきたい。
ファイルを丸ごとコピーしてバックアップする方法もありますが、作業が進むと「どこをどう変更したか」が把握できなくなりますし、手動での統合はミスの原因になります。
Git には、この課題を安全に解決するための仕組みが標準で備わっています。それが branch です。
branch と merge
INPUT · スライド
01 / 11
いま動いているコードに大きな機能追加や改修を入れたい。でも失敗したときにすぐ元の安全な状態へ戻せるようにしておきたい。
ファイルを丸ごとコピーしてバックアップする方法もありますが、作業が進むと「どこをどう変更したか」が把握できなくなりますし、手動での統合はミスの原因になります。
Git には、この課題を安全に解決するための仕組みが標準で備わっています。それが branch です。
02 / 11
第1章で commit が点として積み上がる履歴を見ました。branch は、その commit 履歴を特定の地点から枝分かれさせた独立した作業履歴です。
branch を分けたあとは、それぞれの branch で独立して commit を積み重ねることができます。片方の branch でファイルをどれだけ変更しても、もう一方の branch には一切影響しません。
そして検証が完了したら、変更を1つの branch に merge(統合)します。これが Git による並行開発の最大の強みです。
03 / 11
引数なしで git branch を実行すると、local branch の一覧が表示されます。* 印がついている branch が現在チェックアウト(作業中)している branch です。
git branch <branch名> と branch 名を指定して実行すると、現在の commit から新しい branch を作成します。ただし作成するだけで、branch の切り替えは行われません。
$ git branch* main$ git branch draft$ git branch draft* main04 / 11
作業 branch を切り替えるには git switch <branch名> を実行します。-c オプションをつけると branch の作成と切り替えを同時に実行できます(現場で最も多用されるコマンドです)。
branch を切り替えると、working tree のファイルが切り替え先 branch の commit 状態に即座に入れ替わります。ファイルが消えたわけではなく、元の branch の commit に安全に保存されています。
$ git switch -c new-menuSwitched to a new branch 'new-menu'05 / 11
working tree に未 commit の変更を残したまま branch を切り替えようとすると、Git からエラー(切り替え拒否)が出ます。
これは「どちらの branch に属する変更か特定できず、作業内容の上書きや紛失を防ぐため」の安全機能です。branch を切り替える前に、git add と git commit で変更を確定させておきましょう。
git status で nothing to commit, working tree clean と表示されていれば、安全に branch を切り替えられます。
$ git switch mainerror: Your local changes would be overwritten by switch.06 / 11
branch での開発が完了したら、merge 先の branch に切り替えてから git merge <merge元branch名> を実行します。
手順の順序が重要です。main branch に new-menu branch の変更を取り込みたい場合は、まず git switch main で main に移動し、その上で git merge new-menu を実行します。「どこに統合するか」は、現在いる branch で決まります。
$ git switch main$ git merge new-menuUpdating 3b7e5d1..9f2a1c4Fast-forward07 / 11
merge 実行時に Fast-forward と表示された場合、新しい merge commit は作成されません。
分岐後に main 側で新たな commit が1つも進んでいなかったため、main の branch ポインタ(参照先 commit)を merge 元 branch の最新 commit まで前進させるだけで統合が完了したことを意味します。
履歴グラフ上でも commit の分岐・合流線は生まれず、1本の直線的な履歴のまま進みます。
08 / 11
branch 分岐後に両方の branch でそれぞれ新しい commit が積み上がっていた場合、Fast-forward はできません。
この場合、Git は両 branch の変更を統合した新しい commit を自動生成します。これを merge commit と呼び、親 commit を2つ持つのが特徴です。
commit グラフ上では、2本に分かれていた履歴の線が merge commit で1本に合流する形になります。
$ git merge sideMerge made by the "ort" strategy.09 / 11
同じファイルの同じ行(または近接する行)を両方の branch で異なる内容に変更していた場合、Git は自動 merge を停止します。これが conflict(競合) です。
エラーではありません。「両方の変更内容が重複しており、どちらを採用すべきか人間が判断してください」と Git が確認を求めて作業を安全に停止した状態です。
異なる行の変更であれば Git が自動で両方を反映するため、conflict は発生しません。
$ git merge ramenCONFLICT (content): Merge conflict in menu.txtAutomatic merge failed; fix conflicts and then commit the result.10 / 11
conflict が発生したファイルを開くと、Git による conflict マーカーが挿入されています。
マーカーの構造:
- <<<<<<< HEAD 〜 ======= … 現在チェックアウトしている branch の内容
- ======= 〜 >>>>>>> <branch名> … merge しようとしている branch の内容
解消手順は、マーカー行(<<<<<<<, =======, >>>>>>>)をすべて削除し、最終的に残したいコード・文章にファイルを編集・保存することです。
編集完了後、git add <ファイル名> で解消済みとして stage し、git commit を実行して merge commit を記録します。
<<<<<<< HEADうどん=======ラーメン>>>>>>> ramen11 / 11
conflict の発生時に「今は merge を取りやめて元の状態に戻したい」と判断した場合は、git merge --abort を実行します。
working tree と index が merge を実行する直前のクリーンな状態に完全にロールバックされます。
ファイルを壊さずに安全にやり直せるため、判断に迷ったときや作業を仕切り直したいときは迷わず活用しましょう。