ブランチと手術

マージオプション

普通のマージはボタン1つで、ほとんどの場合それで話は終わります。このページは それ以外のときのためのものです。マージのたびに衝突するロックファイル、誰かが インデントを直したファイル、パスが噛み合わないベンダリング済みプロジェクト。 git には3つとも何年も前からスイッチが用意されています。ただ、コンフリクトの 最中には誰も開かないマニュアルページの中に埋もれているだけです。

ブランチを右クリック → オプション付きでマージ… — サイドバーのブランチ行と リモート行、および グラフ上の色付き ref バッジ(両者は同じメニューブロックを 共有しています)から — あるいは ⌘K → オプション付きでマージ。

オプション付きマージ。実行される git コマンドがそのまま下に書き出される

コマンドは組み立てるそばから表示されます。マニュアルと突き合わせて確かめるため、 そして次回はこのダイアログを使わずにターミナルから実行するために、そこにあります。

ハンクが衝突したとき

選択肢 フラグ 意味
止めて確認する — 既定。自分で解決します
このブランチ側を残す -X ours 衝突したハンクは、すでにチェックアウトされている内容で解決されます
入ってくる側を採用する -X theirs 衝突したハンクは、入ってくるブランチの内容で解決されます

-X ours は -s ours ではありません。 ここのスイッチが決めるのは、実際に 衝突したハンクだけです。もう一方のブランチのそれ以外の変更は、通常どおりマージ されます。ours という名前の ストラテジー — Gitcito は提供していません — は あなたのツリーをまるごと採用してもう一方を捨て去り、含んでいない作業を含んで いると主張するマージコミットを作ります。この区別こそ、git のマージにまつわる 最大の誤解です。

すべてを決められるわけではありません。 変更/削除のコンフリクト — 一方が ファイルを編集し、もう一方が削除した — は内容のハンクではないので、-X は それをあなたに委ねます。それが正しい挙動です。削除されたファイルを復活させる べきかどうかに答えられる「ours 優先」など存在しないからです。

空白

選択肢 フラグ
既存の空白の変更を無視する -X ignore-space-change
空白を完全に無視する -X ignore-space-at-eol、-X ignore-all-space

これが存在する理由となる状況。片方のブランチがファイルのインデントを直し (あるいはフォーマッタが直し)、もう片方が同じ行を編集した。git は1つの行に 対する2つの編集を見て停止します。空白を無視すれば、インデントの変更は天秤に かける変更ではなくなり、本当の編集がマージを通り抜けます。

結果には、触れた行について もう一方 の側の空白が残るので、あとでフォーマッタを かけ直すのは悪くない考えです。

何を記録するか

選択肢 フラグ 手元に残るもの
可能ならファストフォワード — 履歴が分岐していたときだけマージコミット
常にマージコミットを作る --no-ff ファストフォワードでもマージコミット。ブランチがグラフに永久に見えるようになります
ファストフォワードのみ、無理なら拒否 --ff-only 本当のマージが必要なら、何も残りません。チェックとして便利です
Squash --squash 変更はステージされ、マージは記録されず、コミット文はあなたが書きます
マージするがコミットはしない --no-commit マージはステージされ進行中のまま。先に中身を確認したり手を入れたりできます

Squash と --no-commit は同じではありません。 squash はマージがあったこと 自体を忘れます。git は2つ目の親を記録せず、次回そのブランチは未マージに見えます。 --no-commit は単にあなたを待っている進行中のマージです — MERGE_HEAD が 設定されており、コミットすれば通常どおり完了します。

--ff-only は黙って失敗しません。 マージコミットが必要になる場合、git は 拒否して何も動かしません。それこそが、スクリプト化されたマージの前の健全性 チェックとして優れている理由です。

ストラテジー

ストラテジー 用途
既定(ort) すべて。git の現代的な3方向マージ
subtree 双方が別のパスに存在する場合 — このリポジトリのサブディレクトリにベンダリングされたプロジェクトなど
resolve 古い3方向マージ。交差した履歴で ort が諦める場面で、たまに成功します

覚えておく価値があるのは -s subtree です。vendor/parser/ にあるプロジェクトの 更新をマージすると、そうでなければ「全ファイル削除、全ファイル追加」と読まれて しまいます。subtree ストラテジーは先にパスのずれを割り出します。全体の流れは サブツリー を参照してください。

なぜこれが衝突するのか

コンフリクト解決画面 の中には なぜこれが衝突するのか という ボタンがあります。目の前のファイルに対して git log --merge を実行し、ブランチが 分かれてからそのファイルに触れたコミットを、側ごとに一覧します。

コンフリクトしたファイルに触れた、それぞれの側のコミット

コンフリクトマーカーが言うのは 何が 衝突しているかです。こちらが言うのは 誰が、いつ、なぜ変更したか — たいていの場合、解決を実際に左右するのはこちらの 問いであり、どちらかの側を選ぶ前に誰かに聞きに行く理由になります。

何も表示されない場合、どちらの側もこのファイルそのものへの変更をコミットして いません。衝突はもっと上位でのリネームやディレクトリの移動から来ています。

知っておくべき制限

  • オプションは1回のマージにしか効きません。 記憶されませんし、通常の 現在のブランチにマージ の項目やドラッグ&ドロップのメニューを変えることも ありません。
  • 取り消しは変わらず機能します: オプション付きで実行したマージも同じ取り消し エントリを記録し、ORIG_HEAD にリセットします。
  • オクトパスマージ(3つ以上のブランチを一度に)はここでは提供しません。
  • コミットメニューの ref ごとの「X を Y にマージ」項目 は通常のマージのままです。 オプションが欲しいときは ref バッジ自体を使ってください。
  • -X は黙って決めます。 どのハンクが自動解決されたかは何も示されないので、 重要なマージではコンフリクトが出なかったことを信用せず、あとで差分を読んで ください。

関連項目: マージとリベース · コンフリクト · サブツリー · コンフリクトレーダー

この翻訳を GitHub で改善