【Git】pull後に大量のマージコミットが発生したときの原因と履歴整理方法

【Git】pull後に大量のマージコミットが発生したときの原因と履歴整理方法 Git

pullのたびにマージコミットが雪だるま式に増え、履歴が読みにくくなることがあります。
これはgit pullの既定動作が「フェッチ+マージ」であることに起因し、ローカルに自分のコミットが残った状態でリモートを取り込むたびに新しいマージコミットが積み重なるためです。
本記事では、この現象の原因を整理し、既に膨らんだ履歴の整理手順と、今後の再発防止設定を解説します。

なぜ大量のマージコミットが発生するのか

git pullは既定で「マージ」を行います。自分のブランチにローカルコミットが1件でもあると、リモートの先端を取り込む段階で分岐を統合するマージコミットが必ず1つ生まれます。
これを繰り返すと、実質的な作業内容とは無関係な統合点が履歴に連発し、レビューや原因追跡が困難になります。
また、フェッチ後に--ff-onlyで早送りできる場面でも、既定のマージを使うと不要なマージコミットが作られてしまいます。

まず現状を診断する

先祖関係と分岐状況を確認し、どこから直線化すべきかを見極めます。不要な参照を掃除してからログを可視化します。

# 最新の参照を取得して不要参照を掃除
git fetch --prune

# 位置関係を可視化(分岐が多い場合は -n 行数を増やす)
git log --oneline --decorate --graph --all -n 50

# 現在のupstream(追跡先)も確認
git rev-parse --abbrev-ref --symbolic-full-name @{u}

履歴を整理する:ローカルのみ汚れている場合(未push)

まだリモートへ公開していない場合は、リベースで直線化するのが安全かつ簡単です。自分のコミット列をリモート先端上に付け替えます。

# 例:mainブランチで、自分の作業を直線化
git fetch --prune
git rebase origin/main

# コンフリクトが出たら解消→ステージ→続行
git add .
git rebase --continue

# 途中でやり直す場合
git rebase --abort

作業途中の未ステージ変更がある場合は、退避してからリベースします。設定で自動退避も可能です。

# 一時退避してから
git stash push -m "wip"
git rebase origin/main
git stash pop

# 自動退避を恒久設定
git config --global rebase.autoStash true

履歴を整理する:マージコミットが点在している場合(未push)

マージを含む複雑な履歴を綺麗にしたい場合は、リベースの拡張モードを使います。個々のマージの意味を保ちながら直線化や不要コミットの統合(squash)を行えます。

# マージを保ちつつ並べ替える(必要に応じて対話的に)
git fetch --prune
git rebase --rebase-merges -i origin/main

エディターが開いたら、不要なマージや細かい修正コミットを適宜まとめます。意味のある統合点だけ残すのがコツです。

既にリモートに不要なマージがpushされている場合

共有履歴の書き換えは影響が大きいため、基本はそのまま運用し、以後の履歴を綺麗に保つ方針へ切り替えます。
どうしても整理が必要な場合は、全員の合意と手順周知を行い、--force-with-leaseで安全に上書きします。

# 整理したブランチで、他者の更新を保護しつつ強制push
git push --force-with-lease

実行前にPRベースで変更内容を提示し、CIや保護ブランチの設定、リリースタグへの影響も確認します。既存クローンに対しては再クローンまたは厳密なリセット手順の案内が必要です。

今後の再発防止:pull戦略と既定設定を見直す

直線的な履歴を維持するには、pullの既定を「リベース」に切り替えるか、早送りのみ許可する運用にします。フェッチして差分を確認してから取り込む習慣も有効です。

# pullで常にリベース(直線履歴派)
git config --global pull.rebase true

# 早送りのみ許可(不要なマージコミットを抑止)
git config --global pull.ff only

# 参照掃除を自動化(古い追跡ブランチを放置しない)
git config --global fetch.prune true

開発フローとしては、作業ブランチをこまめにorigin/mainへリベースして同期し、PRはfast-forwardマージ(またはrebaseマージ)を既定にするのが効果的です。マージコミットで統合点を残したいプロジェクトでも、--ff-onlyで不要マージを防ぎ、意味のある統合に限定します。

補足:fast-forward可能な場面での安全な取り込み

リモートが先行していて自分のローカルに追加コミットがないなら、早送りだけで履歴を汚さずに同期できます。

# 例:mainブランチの早送り反映
git fetch --prune
git merge --ff-only origin/main
# あるいは
git pull --ff-only

まとめ

pull後にマージコミットが増殖する主因は、既定の「マージ取り込み」をローカルコミットのある状態で繰り返すことにあります。
未pushならリベースで直線化し、複雑な場合は--rebase-mergesを使って整理します。既に共有済みなら、影響範囲を理解したうえで合意のもとに最小限の履歴書き換えを行うか、そのまま維持して以後の運用を改善します。
再発防止にはpull.rebasepull.fffetch.pruneなどの設定を見直し、日常的に「フェッチ→差分確認→適切な取り込み」を徹底することが最も効果的です。