簡単な Git のコンフリクトのパターンと修正(GitHub Desktop で実践)

この記事で学べること

  • コンフリクト(競合)が起きる仕組み
  • よくあるコンフリクトのパターン(最小 6 パターン)
  • GitHub Desktop での解消手順(Pull/Merge 時)
  • 迷ったときの判断基準・チェックリスト
  • 再発させにくくするチーム規約(最低限)

前提

  • GitHub アカウントがある
  • GitHub Desktop をインストール済み
  • 基本操作(Clone/Commit/Push/Pull/Branch 作成)がわかる

用語の最短復習

  • コンフリクト:Git が「どちらが正しい変更かわからない」と判断した状態。
  • 共通祖先:分岐前の共通コミット。マージの基準点。
  • ours / theirs :現在のブランチ(ours)と、取り込む側(theirs)。GitHub Desktop では分かりやすい UI が付くが、ファイル内には <<<<<<< などのマーカーが入る。

よくあるコンフリクト 6 パターン

パターンA:同じ行を別々に編集した(最頻出)

  • 例:Damage = 8; を A が 10 に、B が 12 に変更。
  • 症状:該当行にコンフリクトマーカー。
<<<<<<< HEAD  // 現在ブランチ(ours)
Damage = 10;
=======
Damage = 12;
>>>>>>> feature/b
  • 方針:どちらかを採用、もしくはルールに従って手で統合(例:難易度で切替)。

パターンB:片方が行を削除/片方が編集

  • 例:A はメソッド Heal() を削除、B は Heal() の中身を変更。
  • 症状:ファイル単位または該当ブロックで競合。
  • 方針:削除が正しいか、機能が必要かを判断。必要なら復元して最新の中身で再定義。

パターンC:ファイル名の変更 vs 中身の変更

  • 例:A は Player.cs を Hero.cs にリネーム、B は Player.cs を編集。
  • 症状:リネームと編集が衝突。
  • 方針:名前を採用(Hero.cs)し、B の内容変更も取り込む。最終的に 1 ファイルへ集約。

パターンD:同名ファイルを同時に新規追加

  • 例:A/B どちらも Utils.cs を新規追加(中身は異なる)。
  • 症状:追加の衝突。
  • 方針:ファイルを統合するか、役割で分割(Utils.Text.cs と Utils.Math.cs など)に改名。

パターンE:バイナリ(画像・PSD・.prefab など)

  • 例:A/B が同じ画像を更新。
  • 症状:自動マージ不可。どちらか一方を選ぶしかない場合が多い。
  • 方針:原則は「後から編集した人が、先に入った変更を取り込んで再出力」→ 片方を採用し、必要なら別コミットで差分再適用。

パターンF:設定ファイル(.csproj/package.json など)

  • 例:A がパッケージ X を追加、B がパッケージ Y を追加。
  • 症状:依存の記述行で競合。
  • 方針:両方を残すようにマージし、ビルドで通るか必ず確認。

補足
(Unity):Edit > Project Settings > Editor > Asset Serialization = Force Text にし、.meta を含めてコミット。.unity / .prefab の競合は重い。頻繁に同じシーンを触らない運用・タスク分割を。


GitHub Desktop での解決フロー(基本)

ここでは feature ブランチに main を取り込む ケース(更新取り込み)と、Pull 時に衝突したケースの両方に効く汎用手順を示します。

  1. fetch / pull
    • 右上の Fetch origin を押し、続けて Pull origin
    • コンフリクトがあれば自動で検出され、画面左の「Changes」リストに Conflicted の表示。
  2. 競合ファイルを選択
    • 左ペインでファイルをクリック → 右側に差分ビュー。
    • テキストファイルなら、上部に Choose ours / Choose theirs / Open in External Editor などのボタンが表示。
  3. 解決方法を選ぶ
    • A:片方を丸ごと採用 … 早いが情報を失う可能性。
    • B:手動で統合 … 「Open in External Editor」から VS Code などで編集。
    • ファイル内の競合マーカーを手で消し、最終版だけを残す。
  4. 保存 → GitHub Desktop に戻る
    • 右上に Mark as resolved(または自動検出で Resolved 済み)
    • 競合が複数ある場合は 1 ファイルずつ繰り返す。
  5. テスト(最重要)
    • ビルド/実行で動作確認。単体テストがあれば実行。
  6. まとめてコミット
    • Summary に「Resolve conflicts: …」のように目的を明記。
    • Commit to feature → Push origin
  7. PR の更新/Merge
    • PR で CI が通るか確認し、レビュー → Merge。

代表例で手を動かす(C# の最小例)

事前準備(ブランチ作成)

  1. main を最新化(Fetch/Pull)
  2. New Branch… → feature/damage-tune

変更の衝突を再現

  • A(あなた):Battle.cs のダメージを 10 に
// ours
Damage = 10;
  • B(相手):同じ行を 12 に(GitHub 上で編集でもよい)

取り込みで競合

  • feature/damage-tune を Checkout 中に、Branch > Update from main(※または Pull)
  • Conflicted: Battle.cs

解決(手動統合の例)

  • Open in External Editor → 次のように最終版を決める
int baseDamage = 10;
if (game.Difficulty == Difficulty.Hard) baseDamage = 12;
Damage = baseDamage;
  • 競合マーカーを完全に削除して保存
  • GitHub Desktop に戻り Mark as resolved → Commit
  • ビルドして OK なら Push

迷ったらここを見る:判断フローチャート

  1. どちらの編集が最新の仕様に沿っている?(チケット/仕様書を確認)
  2. 両方の変更を活かせる?(分岐や関数分割で共存)
  3. ビルド・テストは通る?(通らなければ統合が間違い)
  4. 同名追加・改名は役割で分解できる?(Partial/名前分割)
  5. バイナリは更新者が取り込み直せる?(元データ管理)

よくある失敗と回避策

  • 大きな PR を出す → 衝突確率が上がる → 小さく分割。
  • 同じファイルを複数人で長時間ロック → タスクを縦割りせず、横割り分担(UI/ロジック/設定)。
  • レビュー前に main が進む → 「こまめに Update from main」を習慣化。
  • 改名と大規模編集を同時に → ステップを分ける(先にリネームだけの PR)。

チーム最小規約(テンプレ)

  • 1PR の変更は 1トピック に限定。
  • 毎日作業前に Fetch/Pull、PR 前にも Update from main
  • リネーム/移動は単独
  • バイナリはなるべく避け、テキスト化できるものはテキストへ(設定・シーン分割)。
  • コンフリクト解消後は 必ずビルド/テスト

付録:パターン別・最短レシピ一覧

パターン典型例最短の解決手段注意点
同じ行の編集Damage = 10 vs 12片方採用 or 統合動作仕様に合わせる
削除 vs 変更Heal() 削除 vs 本文変更機能要否を判断し復元 or 削除参照呼び出しの存在を確認
改名 vs 変更Player.csHero.cs vs 旧名編集新名に統合旧参照のビルドエラーに注意
追加 vs 追加Utils.cs を双方追加統合 or 名前分割役割の重複を解消
バイナリ画像・PSD・Prefabどちらか採用(更新側で取り込み直し)元データの保全
設定ファイル依存追加の競合両方残し整形ビルドで検証

まとめ

  • コンフリクトは「失敗」ではなく仕様の合流点
  • GitHub Desktop の Conflicted 表示 → 解決 → Mark as resolved → Commit が基本動線。
  • 小さく早くマージし、再発しにくい分担と規約を整えることが最大の防御策。

訪問数 8 回, 今日の訪問数 8回