Gitコンフリクトを3つのステップで解決する実践的な方法

Gitコンフリクトが発生したとき、慌てる必要はありません。この記事では、コンフリクトの原因を理解し、実際に解決するまでの具体的な手順を解説します。実務で今すぐ使える方法をステップバイステップで学べます。

Gitコンフリクトとは何か

Gitコンフリクト(競合)は、複数のブランチで同じファイルの同じ部分を異なる方法で変更したとき、マージ時に発生します。Gitがどちらの変更を採用すべきかを判断できず、開発者の判断を仰ぐ状態です。

コンフリクトは決して異常ではなく、チーム開発では頻繁に発生します。重要なのは、確実に解決するスキルです。

コンフリクトが発生する典型的な場面

  • 複数の開発者が同じファイルを編集し、異なるブランチからマージする
  • リモートブランチと手元のローカルブランチが異なる編集をしている
  • プルリクエスト時に、既にマージされた別のPRと変更が重なっている

ステップ1: コンフリクトを検出する

まず、コンフリクトが本当に発生しているか確認します。

git status

このコマンドを実行すると、以下のような出力が表示されます:

On branch feature/new-feature
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   src/config.js

both modifiedと表示されたファイルがコンフリクトしています。次に、実際にどこでコンフリクトしているか確認しましょう。

git diff

このコマンドでコンフリクト箇所の詳細が表示されます。以下が典型的な形式です。

ステップ2: コンフリクト内容を理解する

ファイルを開くと、以下のようなマーカーが挿入されています:

function getConfig() {
  const setting = {
<<<<<<< HEAD
    apiUrl: 'https://api.example.com/v2',
    timeout: 5000
=======
    apiUrl: 'https://api.example.com/v3',
    timeout: 10000
>>>>>>> feature/update-api
  };
  return setting;
}

このマーカーの意味は以下の通りです:

  • <<<<<<< HEAD:現在のブランチ(マージ先)の内容
  • =======:区切り線
  • >>>>>>> feature/update-api:マージ元ブランチの内容

ここで重要なのは、どちらの変更が正しいのか、またはどちらも必要なのかを判断することです。単なるテキスト削除ではなく、ビジネスロジックの観点から決定してください。

ステップ3: コンフリクトを解決する

方法1: 現在のブランチの変更を採用

自分のブランチの内容を優先したい場合、次のコマンドを実行します:

git checkout --ours src/config.js

これにより、HEADの内容(上側)で統一されます。

方法2: マージ元ブランチの変更を採用

マージ元ブランチの内容を優先したい場合:

git checkout --theirs src/config.js

方法3: 手動で両方の変更を統合(最も推奨)

多くの場合、両方の変更を考慮する必要があります。ファイルエディタでマーカーを削除し、適切に統合します:

function getConfig() {
  const setting = {
    // v3エンドポイントを使用し、タイムアウトを増加
    apiUrl: 'https://api.example.com/v3',
    timeout: 10000
  };
  return setting;
}

手動統合後、ファイルを保存して以下を実行します:

git add src/config.js

全てのコンフリクトを解決したら、コミットして完了です:

git commit -m "Merge branch 'feature/update-api': resolve config endpoint conflict"

ビジュアルツールを使った解決方法

コマンドライン操作に不安がある場合は、ビジュアルマージツールの使用がおすすめです。以下のコマンドで、VS Codeなどのエディタ上で直感的に解決できます:

git mergetool

事前に設定が必要な場合:

git config merge.tool vscode
git config mergetool.vscode.cmd 'code --wait $MERGED'

よくあるハマりポイントと対策

ポイント1: マージを中止したい場合

コンフリクト解決中に判断を誤ったと気づいた場合、マージ全体を中止できます:

git merge --abort

これで元の状態に戻ります。

ポイント2: バイナリファイルのコンフリクト

画像やPDFなどのバイナリファイルでコンフリクトが発生した場合、--oursまたは--theirsで一方を選択するしかありません。デザインデータなど重要なファイルの場合は、チーム内で対象ファイルを統合してください。

ポイント3: マージ後の検証忘れ

手動でコンフリクトを解決した後、必ずコードをテストしてください。特にロジックに関わる部分は、単体テストと統合テストの両方を実行してから本番環境にデプロイしましょう。

npm test  # JavaScriptの場合
python -m pytest  # Pythonの場合

コンフリクトを事前に防ぐベストプラクティス

  • 頻繁にpullする:リモートの最新状態を定期的に取得して、ズレを最小化
  • 小さいPRで分割:1つのPRで変更範囲が大きすぎると、コンフリクト確率が上昇
  • ブランチ戦略の統一:チーム全体でGit Flowなどのブランチ戦略を採用
  • コードレビューの活性化:マージ前にレビューを厳密に行い、問題を早期に発見

よくある質問

一括処理のコマンドがあります:

コンフリクト自体の発生確率は変わりませんが、解決の複雑さが異なります。マージ(merge)は1度のコンフリクト解決で済みますが、リベース(rebase)は複数コミットがある場合、各コミットごとにコンフリクト解決が必要になる可能性があります。チーム向けにはgit mergeの方が安全です。

既にコミットされている場合、git revertでそのコミットを取り消し、改めてマージし直す方法があります。ただし、履歴が複雑になるため、可能なら早めに対応することをお勧めします。

まとめ

  • コンフリクト検出git statusgit diffで状況を把握する
  • 内容確認<<<<<<<=======>>>>>>>マーカーで両側の変更を理解する
  • 判断と統合:ビジネスロジックに基づいて--ours--theirs、または手動統合を選択
  • コミットと検証:統合後は必ずテストを実行して動作確認
  • 事前対策:頻繁なpull、小さいPR、チームでのブランチ戦略統一でコンフリクト自体を減らす

Gitコンフリクトは、チーム開発では避けられない現象です。しかし正しい手順を身につけることで、迅速かつ正確に対応できます。今回解説した3つのステップを意識して、実務で活用してください。

Git公式ドキュメント: git-mergeで、より詳細な使用例を参照できます。

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