← ブログに戻る

Gitマージコンフリクトをビジュアルに解決する — ステップバイステップガイド

tutorial git merge

なぜmergeコンフリクトは開発者を怖がらせるのか(そしてなぜ怖がる必要がないのか)

Gitをしばらく使っていれば、恐ろしいmergeコンフリクトに遭遇したことがほぼ間違いなくあるでしょう。Gitが変更を自動的にmergeできないと告げてくる瞬間は、壁にぶつかったように感じるかもしれません。多くの開発者、特にキャリアの初期にいる人は、mergeコンフリクトを何かがうまくいかなかった証拠だと捉えがちです。しかし真実はもっとシンプルです。mergeコンフリクトは共同開発における正常な一部なのです。効率的に解決するための正しいアプローチが必要なだけです。

mergeコンフリクトとは何か?

mergeコンフリクトは、Gitが2つの異なるbranchからの変更を自動的に統合できないときに発生します。これは通常、2人の開発者(または同じ人が異なるbranchで)が同じファイルの同じ行を編集したときに起こります。

Gitがコンフリクトを検出すると、影響を受けるファイルに直接コンフリクトマーカーを挿入します:

<<<<<<< HEAD
const timeout = 5000;
=======
const timeout = 10000;
>>>>>>> feature/update-timeout

<<<<<<< HEAD=======の間にあるものはすべてあなたのバージョン(しばしば"ours"と呼ばれます)です。=======>>>>>>>の間にあるものは受信バージョン("theirs")です。あなたの仕事は最終結果がどうあるべきかを決め、マーカーを削除し、コンフリクトが解決されたことをGitに伝えることです。

従来の方法:コンフリクトマーカーを手動で編集する

最も基本的なアプローチは、コンフリクトが発生したファイルをテキストエディタで開き、すべてのコンフリクトマーカーを見つけ、手動でコードを編集することです。小さなファイルの単一のコンフリクトであれば、これでうまくいきます。しかし、以下のような状況ではすぐに大変になります:

  • 1つのファイルに散らばった複数のコンフリクト
  • 同じmergeで複数のコンフリクトファイルがある場合
  • 両方のバージョンの一部を組み合わせる必要がある複雑な変更
  • マーカーが読みにくいネストされた、または隣接するコンフリクト

マーカーを手動で編集するのはエラーが起きやすい作業です。うっかりマーカーを残してしまったり、間違ったブロックを削除したり、各バージョンが何をしようとしていたかを見失って微妙なバグを導入してしまうことが簡単に起こります。もっと良い方法があるはずです。

ビジュアルな方法:3ウェイmergeエディタを使う

3ウェイmergeとは?

3ウェイmergeは、ファイルの3つのバージョンを同時に表示します:

  • Base -- 共通の祖先、つまりどちらのbranchも変更を加える前のファイルのバージョン
  • Ours -- あなたのbranchのファイルバージョン
  • Theirs -- 受信branchのファイルバージョン

3つのバージョンすべてを同時に見られることは大きな変革です。コンフリクトマーカーを見つめて何が起こったかを再構築しようとする代わりに、オリジナルに対して各側が正確に何を変更したかを確認できます。このコンテキストにより、各コンフリクトをどのように解決するかの判断がはるかに容易になります。

GitSquidでの仕組み

GitSquidには、コンフリクト解決を簡単にするための3ウェイmergeエディタが組み込まれています。初めてコンフリクトを解決する場合でも安心です。ワークフローは次のようになります:

1. すべてのコンフリクトファイルを一目で確認。 mergeがコンフリクトを生成すると、コンフリクトパネルに影響を受けるすべてのファイルがリストされます。解決する必要がある範囲がすぐにわかります。

2. 3ウェイエディタを開く。 任意のコンフリクトファイルをクリックしてmergeエディタで開きます。3つのカラムが並んで表示されます:左にBase、中央にOurs、右にTheirs。各カラムはシンタックスハイライト付きでファイルの全内容を表示するので、コンテキストの中でコードを読むことができます。

3. ブロックごとにコンフリクトを解決。 各コンフリクトはハイライトされ、個別のブロックとして表示されます。各コンフリクトに対して、明確なアクションボタンが用意されています:

  • Use Ours -- コンフリクトしているコードのあなたのバージョンを保持
  • Use Theirs -- 代わりに受信バージョンを採用
  • Use Both -- 両方の変更を順番に含める

ワンクリックでコンフリクトが解決されます。マーカーを探す必要も、間違った行を誤って削除するリスクもありません。

4. 結果を微調整。 3つのカラムの下にある結果パネルには、CodeMirror 6によるシンタックスハイライト付きのフルコードエディタでmerge結果が表示されます。ワンクリックオプションのいずれも必要な結果を正確に生成しない場合、結果を直接編集できます。これは、一方のbranchの関数シグネチャを保持しつつ、もう一方のbranchの実装を使うなど、両方のバージョンの一部をカスタムで組み合わせる必要がある場合に便利です。

5. 解決済みとしてマーク。 結果に満足したら、ファイルを解決済みとしてマークし、次のコンフリクトファイルに進みます。すべてのファイルが解決されたら、mergeを完了できます。

重要な利点は、コンテキストを失わないことです。どちらのbranchも触れる前のコードの状態、各branchが何を変更したか、最終結果がどうなるかを常に確認できます。この明確さが、mergeコンフリクトにまつわる不安の大部分を取り除きます。

mergeコンフリクトを避けるためのヒント

優れたツールがあっても、コンフリクトを解決するよりも最初から防ぐ方が常に良いです。役立つ実践的な習慣をいくつか紹介します:

  • こまめにpullする。 メインbranchからの変更を統合せずに放置する時間が長いほど、チームメイトの作業からコードが乖離していきます。定期的にpullすることでその差を小さく保ち、編集が重複する可能性を減らせます。
  • branchを短命に保つ。 2週間存続するfeature branchは、2日しか存続しないものよりもはるかに多くの潜在的なコンフリクトを蓄積します。大きな機能をより小さな、mergeしやすい単位に分割しましょう。
  • チームとコミュニケーションを取る。 2人が同じファイルやモジュールで作業する必要がある場合、ちょっとした連絡が後で時間を節約できます。調整は形式的である必要はありません。短いメッセージで十分なことが多いです。
  • feature flagsを使う。 リリース準備ができていない機能のために長期間のbranchを維持する代わりに、feature flagの裏側でmergeしましょう。コードは継続的に統合されますが、機能は完成するまで非表示のままです。

mergeコンフリクトは正常なこと

mergeコンフリクトは何かがうまくいかなかったサインではありません。複数の人が同じコードベースで作業することの自然な結果であり、それこそがバージョン管理がサポートするために設計されていることなのです。フラストレーションの溜まる体験とスムーズな体験の違いは、通常、使用するツールに帰着します。

ビジュアルな3ウェイmergeエディタは推測作業をなくします。テキストエディタでコンフリクトマーカーを解読する代わりに、コードのすべてのバージョンを見て、理にかなった解決策を選び、先に進むことができます。GitSquidの組み込みmergeエディタを使えば、コンフリクトの解決は恐れるべきものではなく、ワークフローの一部になります。