簡単な 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 時に衝突したケースの両方に効く汎用手順を示します。
- fetch / pull
- 右上の Fetch origin を押し、続けて Pull origin。
- コンフリクトがあれば自動で検出され、画面左の「Changes」リストに Conflicted の表示。
- 競合ファイルを選択
- 左ペインでファイルをクリック → 右側に差分ビュー。
- テキストファイルなら、上部に Choose ours / Choose theirs / Open in External Editor などのボタンが表示。
- 解決方法を選ぶ
- A:片方を丸ごと採用 … 早いが情報を失う可能性。
- B:手動で統合 … 「Open in External Editor」から VS Code などで編集。
- ファイル内の競合マーカーを手で消し、最終版だけを残す。
- 保存 → GitHub Desktop に戻る
- 右上に Mark as resolved(または自動検出で Resolved 済み)
- 競合が複数ある場合は 1 ファイルずつ繰り返す。
- テスト(最重要)
- ビルド/実行で動作確認。単体テストがあれば実行。
- まとめてコミット
- Summary に「Resolve conflicts: …」のように目的を明記。
- Commit to feature → Push origin。
- PR の更新/Merge
- PR で CI が通るか確認し、レビュー → Merge。
代表例で手を動かす(C# の最小例)
事前準備(ブランチ作成)
main
を最新化(Fetch/Pull)- 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
迷ったらここを見る:判断フローチャート
- どちらの編集が最新の仕様に沿っている?(チケット/仕様書を確認)
- 両方の変更を活かせる?(分岐や関数分割で共存)
- ビルド・テストは通る?(通らなければ統合が間違い)
- 同名追加・改名は役割で分解できる?(Partial/名前分割)
- バイナリは更新者が取り込み直せる?(元データ管理)
よくある失敗と回避策
- 大きな 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.cs →Hero.cs vs 旧名編集 | 新名に統合 | 旧参照のビルドエラーに注意 |
追加 vs 追加 | Utils.cs を双方追加 | 統合 or 名前分割 | 役割の重複を解消 |
バイナリ | 画像・PSD・Prefab | どちらか採用(更新側で取り込み直し) | 元データの保全 |
設定ファイル | 依存追加の競合 | 両方残し整形 | ビルドで検証 |
まとめ
- コンフリクトは「失敗」ではなく仕様の合流点。
- GitHub Desktop の Conflicted 表示 → 解決 → Mark as resolved → Commit が基本動線。
- 小さく早くマージし、再発しにくい分担と規約を整えることが最大の防御策。
訪問数 8 回, 今日の訪問数 8回
ディスカッション
コメント一覧
まだ、コメントがありません