git mergeコンフリクトを3ステップで確実に解消する実践法

git mergeでコンフリクトが発生したとき、落ち着いて対応できるかがエンジニアのスキルの差です。この記事では、コンフリクト検出から解消、マージ完了まで、実務で即座に使える手順を解説します。

git mergeコンフリクトが起こる仕組み

git mergeコンフリクトは、同じファイルの同じ部分を異なるブランチで異なる方法で編集したときに発生します。Gitはどちらの変更を優先すべきか判断できないため、手動での解決を待ちます。

特に複数人で開発する場合、このコンフリクトは避けて通れません。重要なのは、焦らず体系的に対応することです。

ステップ1:コンフリクトを正確に把握する

コンフリクト状態の確認

まずは現在の状態を確認しましょう。以下のコマンドでコンフリクトの詳細が表示されます。

git status

出力例:

On branch feature/add-login
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

both modified:   src/auth.js
both modified:   src/config.js

このように「both modified」と表示されたファイルが、コンフリクトが発生しているファイルです。

コンフリクト箇所の特定

実際のファイルを開いて、コンフリクト箇所を確認します。

cat src/auth.js

コンフリクト箇所は以下のように表示されています:

<<<<<<< HEAD
// 現在のブランチ(ローカル)の内容
function authenticate(username, password) {
  return validateUser(username, password);
}
=======
// マージしようとしているブランチの内容
function authenticate(username, password) {
  return validateUserWithEncryption(username, password);
}
>>>>>>> origin/main

この区切り線の意味を理解することが最初の一歩です。

ステップ2:コンフリクトを手動で解決する

どちらの変更を採用するか判断する

コンフリクト箇所を見つけたら、以下の3つの選択肢があります:

  • 現在のブランチを採用:HEAD側(<<<<<<<〜=======の部分)を残す
  • マージ元ブランチを採用:=======〜>>>>>>>の部分を残す
  • 両方を組み合わせる:適切にコードを修正して、両方の機能を統合する

最適な判断には、チームのコンテキストが必要です。急いで決めず、必ず関連メンバーに確認しましょう。

手動マージの実例

以下の例では、暗号化機能を追加しつつ、既存ロジックも保持する判断をしたとします。

// 修正前(コンフリクト状態)
<<<<<<< HEAD
function authenticate(username, password) {
  return validateUser(username, password);
}
=======
function authenticate(username, password) {
  return validateUserWithEncryption(username, password);
}
>>>>>>> origin/main

// 修正後(両方の機能を統合)
function authenticate(username, password) {
  // 基本的なバリデーション
  if (!username || !password) {
    return false;
  }
  // 暗号化されたバリデーションを実行
  return validateUserWithEncryption(username, password);
}

重要なのは、単に一方を選ぶのではなく、ビジネスロジックに基づいて意思決定することです。

よくあるハマりポイント:マーカーの完全削除

解決後、必ず以下のマーカーが完全に削除されていることを確認してください:

<<<<<<<
=======
>>>>>>>

これらが残っていると、ファイルが壊れたコード状態になります。

ステップ3:マージを確定する

修正したファイルをステージング

すべてのコンフリクトを解決したら、修正したファイルをGitに通知します。

git add src/auth.js src/config.js

または、すべてのコンフリクト解決ファイルを一度に追加:

git add -A

マージコミットを作成

ステージング後、マージコミットを実行します。

git commit -m "Merge branch 'origin/main' into feature/add-login

Resolved conflicts in src/auth.js and src/config.js:
- Integrated encryption validation with existing user validation
- Maintained backward compatibility"

コミットメッセージに、何をなぜ決断したかを書くことで、後から履歴をたどるときに判断基準が明確になります。

マージ完了の確認

以下のコマンドで、マージが正常に完了したか確認します。

git status

出力が以下のようになれば成功です:

On branch feature/add-login
nothing to commit, working tree clean

コンフリクト解決時の実用的なツール

視覚的にコンフリクトを解決したい場合

手動編集が複雑な場合、マージツールを使うと効率的です。

git mergetool

このコマンドで、VSCodeやMerge Toolなどのグラフィカルツールを起動できます(設定済みの場合)。

特定ファイルで一方を採用したい場合

複雑な判断が不要な場合、以下のコマンドで素早く決定できます。

// 現在のブランチ(HEAD)を採用
git checkout --ours src/auth.js

// マージ元を採用
git checkout --theirs src/config.js

マージを中断したい場合

途中で判断が難しくなったら、マージ自体をキャンセルできます。

git merge --abort

このコマンドで、マージ前の状態に完全に戻ります。

本番環境での失敗を防ぐチェックリスト

  • コンフリクトマーカー(<<<、===、>>>)がすべて削除されているか確認
  • 修正後のコードが実際に動作するかローカルでテスト実行
  • linterやビルドコマンドを実行して、構文エラーがないか検証
  • テストスイートを実行して、既存機能が壊れていないか確認
  • コミットメッセージに判断理由を記載して、チームの理解を促進

git mergeを使うべき場面と使うべきでない場面

git mergeを使うべき場面:複数ブランチが定期的に統合される開発フロー(GitFlowやマスターベースの開発)、チーム全体で履歴の透明性が必要な場合。

代替手段の検討:線形な履歴を好む場合はgit rebaseを、さらにシンプルな履歴を保ちたい場合はSquash mergeを検討してください。

よくある質問

はい。コンフリクト解決後、git commitでマージコミットを作成する必要があります。このコミット自体がマージの記録になり、後から何が起きたかを追跡できます。

必ずローカルでテストを実行してください。特にNode.jsプロジェクトであればnpm test、Pythonならpytestなど。修正内容が実装要件を満たしているか確認してからプッシュしましょう。

可能です。git merge --abortでマージ全体をキャンセルするか、まだプッシュしていなければgit reset --hard HEAD~1で前のコミット状態に戻せます。ただし、プッシュ後はgit revertで対応します。

まとめ

  • コンフリクトは自然に発生するものであり、問題ではなく判断のチャンス
  • git statusで状態を把握し、ファイルを開いてコンフリクトマーカーを確認する
  • 単に一方を選ぶのではなく、ビジネスロジックに基づいて両方を統合することを検討する
  • 修正後はgit addgit commitで確定し、必ず理由を書く
  • マージツール(git mergetool)やgit checkout --ours/--theirsを活用して効率化する
  • プッシュ前に必ずローカルでテストを実行して、修正内容が機能していることを確認する

Git公式ドキュメント:Basic Branching and Mergingも参考になります。

テスト環境:macOS 14 / Git 2.42.1 / VS Code 1.85で動作確認済み

K
AWS・Python・生成AIを専門とするソフトウェアエンジニア。AI・クラウド・開発ワークフローの実践ガイドを執筆しています。詳しく見る →