Gitの無関係な履歴のマージ拒否対処法
冒頭まとめ git pullやgit mergeで次のエラーが出る場合、Gitは結合する二つの履歴に共通の祖先となるコミットを見つけられていません。コミットは、変更内容を記録した単位です。 fatal: refusing to merge unrelated histories 通信をやり直すだけでは解消しません。接続先と対象ブランチを確認し、独立した二つの履歴を本当に結合したい場合だけ、--allow-unrelated-historiesを指定します。 git fetch origin git merge --allow-unrelated-histories origin/main originとmainは例です。実際の接続先とブランチ名に置き換えてください。このオプションは履歴の結合を許可するだけで、ファイルの競合を自動で解消するものではありません。 エラーが出る条件とGitの版 Gitのmerge公式文書は、共通の祖先がない履歴の結合を既定で拒否すると説明しています。独立して始まったプロジェクトの履歴を結合するための例外が、--allow-unrelated-historiesです。 この拒否はGit 2.9のリリースノートに記録されています。それ以前の既定動作は、共通の祖先がない履歴の結合も許可するものでした。別に作られた履歴が意図せず既存プロジェクトへ混ざることを防ぐため、動作が変更されました。 git pullでも、取得した履歴をマージで取り込む場合にこの判定が働きます。pullには履歴を組み直すrebase方式もあり、今回のオプションはマージ方式で使うものです。 ファイルの内容が同じでも、別々に作った最初のコミットが同じ履歴になるとは限りません。判断対象はファイルの一致ではなく、コミット間の親子関係です。 接続先と共通の祖先を確認する 最初に、別のプロジェクトを接続先に指定していないかを確認します。 git status git remote -v git branch --show-current git fetch origin git log --oneline --graph --decorate --all git merge-base HEAD origin/main git fetchはリモートの履歴を取得します。この段階では作業中のブランチへマージしません。取得後のorigin/mainと、現在のコミットを表すHEADを比べます。 merge-baseの公式文書によると、このコマンドは二つのコミットの共通祖先を探します。この記事のGit 2.51.1による確認では、独立した履歴に対して標準出力は空、終了コードは1でした。 ただし、出力がないだけで判断しないでください。ブランチ名が誤っているなどのエラーが表示された場合は、先にその問題を直します。 履歴を途中までしか取得していない浅いリポジトリでは、祖先をたどる情報が不足する場合もあります。 git rev-parse --is-shallow-repository trueなら、接続先を確認したうえで履歴全体を取得し、再確認します。 git fetch --unshallow origin git merge-base HEAD origin/main 浅い履歴の取得方法はfetchの公式文書に説明されています。共通の祖先が見つからない理由を確認する前に、結合の許可へ進まないようにします。 別々の初期化で二つの履歴ができる GitHubでREADME付きのリポジトリを作り、手元でも別にgit initしてコミットすると、それぞれ独立した最初のコミットができます。そこへ接続先を追加しても、過去の履歴の親子関係は変わりません。 ...