症状

GitHubでプルリクエスト(PR)を作成またはマージしようとすると「This branch has conflicts that must be resolved」と表示される。

結論:まずこれを確認

  1. ローカルで最新の main(またはベースブランチ)を取得する
  2. 作業ブランチにマージまたはリベースしてコンフリクトを解消する
  3. 解消後にプッシュしてPRを更新する

操作フロー

    flowchart TD
    A[PRでコンフリクト発生] --> B{ローカルで解消?<br>GitHub上で解消?}
    B -->|ローカル| C[最新のbaseブランチを取得]
    B -->|GitHub上| D[Resolve conflicts ボタン]
    C --> E{merge? rebase?}
    E -->|merge| F[git merge main]
    E -->|rebase| G[git rebase main]
    F --> H[コンフリクト箇所を編集]
    G --> H
    D --> H
    H --> I[git add でステージング]
    I --> J{merge? rebase?}
    J -->|merge| K[git commit]
    J -->|rebase| L[git rebase --continue]
    K --> M[git push]
    L --> N[git push --force-with-lease]
    M --> O[PR更新完了]
    N --> O
  

よくある原因

  • ベースブランチが更新された - PR作成後に main に新しいコミットが追加された
  • 同じファイルを複数人が編集 - 同じ行を別々のブランチで変更した
  • ファイルの削除と編集が競合 - 一方が削除、一方が編集した
  • ブランチが古すぎる - 長期間マージされずにベースブランチと乖離した
  • 自動マージツールの限界 - 近接した行の変更は自動解決できない
  • リネームと編集の競合 - ファイル名変更と内容変更が同時に起きた

操作手順

ステップ1: 現在の状態を確認する

    git status
git branch -a
  

🔍 チェックポイント: 作業ブランチにいることを確認する。未コミットの変更がある場合は先にコミットまたはスタッシュする。

ステップ2: ベースブランチの最新を取得する

    git fetch origin
  

🔍 チェックポイント: origin/main が最新になっていることを確認する。

ステップ3: 作業ブランチにベースブランチを取り込む

方法A: merge を使う場合(履歴を残す)

    git checkout feature/my-branch
git merge origin/main
  

方法B: rebase を使う場合(履歴を整理する)

    git checkout feature/my-branch
git rebase origin/main
  

🔍 チェックポイント: コンフリクトがあれば CONFLICT と表示される。コンフリクトファイルの一覧が出力される。

ステップ4: コンフリクトを解消する

コンフリクトファイルを開くと以下のようなマーカーがある:

    <<<<<<< HEAD
自分の変更内容
=======
相手(main)の変更内容
>>>>>>> origin/main
  
  • <<<<<<< HEAD から ======= までが自分の変更
  • ======= から >>>>>>> origin/main までがベースブランチの変更
  • 両方を見比べて、最終的にどうあるべきかを決めて編集する
  • マーカー(<<<<<<<, =======, >>>>>>>)はすべて削除する

🔍 チェックポイント: git status でコンフリクト中のファイルが both modified と表示される。

ステップ5: 解消したファイルをステージングする

    git add ファイル名
# または全ファイルを追加
git add .
  

🔍 チェックポイント: git statusChanges to be committed に移動していることを確認する。

ステップ6: コミットまたはリベース継続

merge の場合

    git commit
# エディタが開く。デフォルトのマージコミットメッセージでよければそのまま保存
  

rebase の場合

    git rebase --continue
# 複数コミットで続けてコンフリクトがあれば、ステップ4-6を繰り返す
  

🔍 チェックポイント: git log --oneline -5 でコミット履歴を確認する。

ステップ7: リモートにプッシュする

merge の場合

    git push origin feature/my-branch
  

rebase の場合

    git push --force-with-lease origin feature/my-branch
  

⚠️ 警告: --force-with-lease は安全な強制プッシュだが、他の人が同じブランチで作業している場合は事前に確認すること。

🔍 チェックポイント: GitHubのPRページでコンフリクトが解消されていることを確認する。

NG行動

  • コンフリクトマーカーを残したままコミット - ビルドエラーや実行時エラーの原因になる
  • 相手の変更を確認せず自分の変更だけ採用 - 他の人の作業が消える
  • git push --force(-with-lease なし)を使う - 他の人のコミットを上書きするリスクがある
  • コンフリクト解消中に git rebase --abort 以外でやり直す - 中途半端な状態になる
  • PR のベースブランチを間違える - 別のブランチとのコンフリクトを解消しても意味がない

よくある質問(FAQ)

Q1: merge と rebase どちらを使うべき?

A: チームのルールに従う。ルールがない場合、コミット履歴を残したいなら merge、履歴を整理したいなら rebase を選択する。rebase は強制プッシュが必要になる点に注意。

Q2: GitHub の「Resolve conflicts」ボタンで解消できる?

A: 単純なコンフリクトなら可能。ただし複雑な変更やバイナリファイルのコンフリクトはローカルで解消する必要がある。

Q3: コンフリクト解消を途中でやめたい

A: merge の場合は git merge --abort、rebase の場合は git rebase --abort で元の状態に戻せる。

関連するトラブル

準備中

解決しない場合