GitHubコンフリクト解消完全ガイド:マージの競合を怖がらずに解決する方法

git

「マージしようとしたらコンフリクトが発生した…」 「どのコードを残せばいいか分からない」 「間違えてコードを消してしまいそうで怖い」

GitHubを使った共同開発で、誰もが一度は経験するコンフリクト(競合)。赤いエラーメッセージを見ると、つい焦ってしまいますよね。

でも大丈夫!コンフリクトは、複数の人が同じプロジェクトを改善しようとしている証拠。適切な手順を踏めば、必ず解決できます。

この記事では、GitHubでのコンフリクト解消について、基本的な仕組みから実践的な解決方法、そして予防策まで、すべてを分かりやすく解説します。この記事を読み終える頃には、コンフリクトを恐れず、自信を持って解決できるようになっているはずです!

スポンサーリンク
  1. コンフリクトの基本理解
    1. そもそもコンフリクトって何?
    2. なぜコンフリクトが発生するの?
  2. コンフリクトの確認方法
    1. コマンドラインでの確認
    2. GitHubのプルリクエストでの確認
  3. コンフリクトマーカーの読み方
    1. コンフリクトマーカーの構造
  4. 基本的なコンフリクト解消手順
    1. ステップ1:コンフリクトの内容を理解
    2. ステップ2:手動でコンフリクトを解消
    3. ステップ3:解消をコミット
  5. VSCodeでのコンフリクト解消
    1. VSCodeの便利な機能
    2. 使い方の手順
  6. GitHub Web UIでの解消
    1. プルリクエストでの解消
  7. 複雑なコンフリクトの対処法
    1. バイナリファイルのコンフリクト
    2. 大規模なコンフリクト
    3. リベース時のコンフリクト
  8. コンフリクトを防ぐベストプラクティス
    1. 1. こまめなプル/フェッチ
    2. 2. 小さな単位でコミット
    3. 3. ブランチ戦略の採用
    4. 4. .gitignoreの適切な設定
  9. チーム開発でのコンフリクト対策
    1. コミュニケーションルール
    2. 自動化ツールの活用
  10. よくあるエラーと対処法
    1. “fatal: refusing to merge unrelated histories”
    2. “error: Your local changes would be overwritten”
    3. “Merge conflict in deleted file”
  11. 緊急時の対処法
    1. マージを取り消したい
    2. 間違えて解消した場合
  12. 実践的な例:典型的なシナリオ
    1. シナリオ1:CSSの競合
    2. シナリオ2:関数の引数変更
  13. よくある質問と回答
    1. Q: コンフリクトを解消したのに、また発生する
    2. Q: どちらの変更を選ぶべきか分からない
    3. Q: 大量のコンフリクトで手に負えない
    4. Q: コンフリクト解消後、テストが失敗する
    5. Q: リベースとマージ、どちらがコンフリクトが少ない?
  14. まとめ:コンフリクトと上手に付き合う

コンフリクトの基本理解

そもそもコンフリクトって何?

コンフリクトを、2人で同じ文書を編集する場面に例えてみましょう。

日常での例:

田中さん:第3段落を「売上は20%増加」に変更
鈴木さん:同じ第3段落を「売上は15%増加」に変更
→ どちらが正しい?これがコンフリクト!

GitHubでも同じことが起きます。同じファイルの同じ場所を、複数の人が異なる内容に変更すると、Gitは自動的にマージできません。

なぜコンフリクトが発生するの?

主な発生パターン:

  1. 同じ行の編集
# developブランチ
price = 1000

# featureブランチ  
price = 1200

→ マージ時にコンフリクト!
  1. ファイルの削除と編集
    • Aさん:ファイルを削除
    • Bさん:同じファイルを編集
  2. 大規模なリファクタリング
    • 複数人が同時に構造を変更

コンフリクトの確認方法

コマンドラインでの確認

# マージを試みる
git merge feature-branch

# コンフリクトが発生した場合の表示
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

# コンフリクトしているファイルを確認
git status

# 出力例
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   index.html
        both modified:   style.css

GitHubのプルリクエストでの確認

プルリクエストページで、以下のような警告が表示されます:

This branch has conflicts that must be resolved
Conflicting files:
• index.html
• style.css

コンフリクトマーカーの読み方

コンフリクトマーカーの構造

コンフリクトが発生すると、ファイル内に特殊なマーカーが挿入されます。

function calculatePrice(quantity) {
<<<<<<< HEAD
    const price = 1000;
    const tax = 0.10;
=======
    const price = 1200;
    const tax = 0.08;
>>>>>>> feature-branch
    return price * quantity * (1 + tax);
}

マーカーの意味:

  • <<<<<<< HEAD:現在のブランチ(マージ先)の内容開始
  • =======:区切り線
  • >>>>>>> feature-branch:マージ元のブランチの内容終了

基本的なコンフリクト解消手順

ステップ1:コンフリクトの内容を理解

# 変更履歴を確認
git log --oneline --graph --all

# 各ブランチの変更内容を確認
git diff HEAD feature-branch

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

// コンフリクト解消前
function calculatePrice(quantity) {
<<<<<<< HEAD
    const price = 1000;
    const tax = 0.10;
=======
    const price = 1200;
    const tax = 0.08;
>>>>>>> feature-branch
    return price * quantity * (1 + tax);
}

// コンフリクト解消後(両方の変更を考慮)
function calculatePrice(quantity) {
    const price = 1200;  // feature-branchの新価格を採用
    const tax = 0.10;    // HEADの税率を維持
    return price * quantity * (1 + tax);
}

ステップ3:解消をコミット

# 解消したファイルをステージング
git add index.html style.css

# コンフリクト解消をコミット
git commit -m "Merge feature-branch: 価格更新と税率維持"

# プッシュ
git push origin main

VSCodeでのコンフリクト解消

VSCodeの便利な機能

VSCodeは、コンフリクト解消を視覚的にサポートします。

インラインアクション:

Accept Current Change  | Accept Incoming Change | Accept Both Changes | Compare Changes

使い方の手順

  1. コンフリクトファイルを開く
    • 色付きでコンフリクト箇所が表示
  2. 選択肢から選ぶ
    • Accept Current Change:現在のブランチの変更を採用
    • Accept Incoming Change:マージ元の変更を採用
    • Accept Both Changes:両方を残す
    • Compare Changes:差分を並べて表示
  3. 手動編集も可能
    • 必要に応じて直接編集
  4. 保存してコミット

GitHub Web UIでの解消

プルリクエストでの解消

手順:

  1. プルリクエストページで「Resolve conflicts」ボタンをクリック
  2. Web エディタが開く
  3. コンフリクトマーカーを手動で編集
  4. 「Mark as resolved」をクリック
  5. 「Commit merge」でコミット

Web UIの利点:

  • ローカル環境不要
  • シンプルなコンフリクトに最適
  • チームメンバーとリアルタイムで確認可能

複雑なコンフリクトの対処法

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

# 画像ファイルなどのバイナリファイルの場合
git checkout --theirs path/to/image.png  # 相手の変更を採用
# または
git checkout --ours path/to/image.png    # 自分の変更を採用

# ステージング
git add path/to/image.png

大規模なコンフリクト

# 3-wayマージツールを使用
git mergetool

# 特定のツールを指定
git mergetool --tool=vimdiff
git mergetool --tool=meld
git mergetool --tool=kdiff3

リベース時のコンフリクト

# リベース開始
git rebase main

# コンフリクト発生時
# 1. コンフリクトを解消
# 2. ステージング
git add .

# 3. リベースを続行
git rebase --continue

# またはスキップ
git rebase --skip

# 中止したい場合
git rebase --abort

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

1. こまめなプル/フェッチ

# 作業開始前に最新を取得
git pull origin main

# またはフェッチしてマージ
git fetch origin
git merge origin/main

2. 小さな単位でコミット

# 機能ごとに小さくコミット
git add -p  # 部分的にステージング
git commit -m "feat: ユーザー認証機能を追加"

# 大きな変更を避ける
# NG: 1000行の変更を1コミット
# OK: 100行ずつ10コミット

3. ブランチ戦略の採用

# feature ブランチを短命に保つ
git checkout -b feature/add-login
# 作業(1-2日で完了)
git checkout main
git merge feature/add-login
git branch -d feature/add-login

4. .gitignoreの適切な設定

# IDEの設定ファイル
.vscode/
.idea/
*.swp

# ビルド生成物
dist/
build/
*.log

# 環境依存ファイル
.env
.env.local

チーム開発でのコンフリクト対策

コミュニケーションルール

## チーム開発ルール

1. **作業開始時の宣言**
   - Slackで「index.jsを編集します」と共有

2. **プルリクエストの活用**
   - 直接mainへのプッシュを禁止
   - レビューを必須化

3. **定期的な同期会**
   - 週1回、各自の作業内容を共有

自動化ツールの活用

# .github/workflows/auto-merge.yml
name: Auto Merge
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  auto-merge:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Check conflicts
        run: |
          git fetch origin main
          git merge-base --is-ancestor origin/main HEAD

よくあるエラーと対処法

“fatal: refusing to merge unrelated histories”

# 解決方法
git pull origin main --allow-unrelated-histories

“error: Your local changes would be overwritten”

# 一時退避してからマージ
git stash
git merge feature-branch
git stash pop

# コンフリクトがある場合は解消

“Merge conflict in deleted file”

# ファイルを削除する場合
git rm conflicted-file.txt

# ファイルを残す場合
git add conflicted-file.txt

緊急時の対処法

マージを取り消したい

# マージをなかったことに
git merge --abort

# すでにコミットした場合
git reset --hard HEAD~1

# リモートにプッシュ済みの場合(慎重に)
git revert -m 1 <merge-commit-hash>

間違えて解消した場合

# reflogで履歴を確認
git reflog

# 特定の状態に戻す
git reset --hard HEAD@{2}

実践的な例:典型的なシナリオ

シナリオ1:CSSの競合

/* main ブランチ */
.button {
    background-color: blue;
    padding: 10px;
}

/* feature ブランチ */
.button {
    background-color: green;
    padding: 15px;
    border-radius: 5px;
}

/* 解消後 */
.button {
    background-color: green;  /* 新しい色を採用 */
    padding: 15px;           /* 新しいパディングを採用 */
    border-radius: 5px;      /* 新機能を追加 */
}

シナリオ2:関数の引数変更

// main ブランチ
function sendEmail(to, subject, body) {
    // 実装
}

// feature ブランチ  
function sendEmail(to, subject, body, attachments = []) {
    // 実装
}

// 解消:後方互換性を保つ
function sendEmail(to, subject, body, attachments = []) {
    // feature ブランチの拡張版を採用
}

よくある質問と回答

Q: コンフリクトを解消したのに、また発生する

A: 他のブランチからの変更が入っている可能性があります。git pull --rebaseで最新を取得してから作業してください。

Q: どちらの変更を選ぶべきか分からない

A: チームメンバーと相談しましょう。コードの作成者に確認するか、プルリクエストのコメントで議論してください。

Q: 大量のコンフリクトで手に負えない

A: 一度に解決せず、ファイルごとに対処しましょう。必要なら、小さなコミットに分割してマージすることも検討してください。

Q: コンフリクト解消後、テストが失敗する

A: 両方の変更を機械的にマージしただけでは、論理的な整合性が取れていない可能性があります。コードレビューとテストを徹底してください。

Q: リベースとマージ、どちらがコンフリクトが少ない?

A: 一般的にマージの方がコンフリクトは少ないですが、履歴が複雑になります。チームの方針に従ってください。

まとめ:コンフリクトと上手に付き合う

GitHubでのコンフリクトは、チーム開発では避けられないものですが、適切に対処すれば問題ありません。

重要なポイント:

  • コンフリクトは悪いことではない
  • 落ち着いて一つずつ解消
  • ツールを活用して効率化
  • コミュニケーションで予防
  • 定期的な同期で最小化

解消の基本ステップ:

  1. コンフリクトの内容を理解
  2. 適切な変更を選択/編集
  3. テストで動作確認
  4. コミットして完了

この記事で学んだ技術を使えば、コンフリクトはもう怖くありません。むしろ、チームでより良いコードを作り上げる機会として捉えることができるでしょう。

さあ、自信を持ってマージボタンを押しましょう!Happy Coding! 🚀

コメント

タイトルとURLをコピーしました