LoginSignup
5
4

More than 1 year has passed since last update.

【コード管理/GitHub】ローカルリポジトリとリモートリポジトリの変更履歴に差があり、git pushが実行できない問題を解決する

Last updated at Posted at 2023-04-12

今回の課題

下記のコマンドで、
リモートリポジトリにpushしようとしたところ、

$ git push origin main

下記のように、
リモートリポジトリの最新情報に対して、ローカルリポジトリの情報が古いため、
リモートリポジトリの情報をローカルリポジトリにpullする必要がある
といった内容のエラーが発生してしまった。

To https://github.com/gussan-me/cloudformation-git.git
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'https://github.com/gussan-me/cloudformation-git.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

結論

下記のコマンドを実行してからgit pushすることで、
無事解決することができた。

$ git fetch origin
$ git reset --hard origin/main

上記のコマンドは簡単に言うと、
リモートブランチの状態に強制的に合わせる
ということを行っている。

git fetch originでリモートリポジトリの最新情報をアップストリームブランチに反映させて、
git reset --hard origin/mainで、アップストリームブランチの内容を強制的にローカルリポジトリを上書きしている。

◼︎参考記事

解決までの手順

解決まで色々試行錯誤したので、メモとして記録しておく。

まず、今回の課題に記載したエラーで、pullをするように指示があったので、pullをしてみた。

$ git pull origin [リモートリポジトリのURL]

すると、下記のように「関連性のない履歴のマージができない」というエラーが発生した。
ローカルリポジトリとリモートリポジトリの変更履歴が異なっているため、エラーが発生してしまった様子。

fatal: refusing to merge unrelated histories

次に、下記の--allow-unrelated-historiesオプションをつけて、git pullを行なった。

$ git pull --allow-unrelated-histories origin main

※このオプションは、異なる変更履歴を持つ2つのブランチをマージするためのもの
 ローカルリモートリポジトリとリモートリポジトリで変更履歴が異なる場合、
 mergeコマンドとpullコマンドではこちらを指定しないとマージできない。

しかし、--allow-unrelated-historiesオプションをつけてpullをしても、
下記のようなエラーが発生してしまい、マージが失敗してしまう状況から抜け出せなかった。

From https://[リモートリポジトリのURL]
 * branch            main       -> FETCH_HEAD
Auto-merging README.md
CONFLICT (add/add): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

このエラーにからは、README.mdというファイルでコンフリクトが発生していることが分かった。
ここまでの全ての行程でエラーが発生してしまっているので、
ここでgit pushを試しても、もちろん最初と同じエラーが発生してしまう...。

最後に下記を試してからgit pushをしてもエラーが発生しなくなった!

$ git fetch origin
$ git reset --hard origin/main

更に詳しく調べてみる

上記までで、エラーは解決することができたが、
更に理解を深めるために色々と調べてみた。

git pullは失敗してgit fetchが成功した理由は?

今回のエラーを解決する過程で、
リモートリポジトリの最新情報をローカルに反映させるgit pull,git fetchという2つのコマンドを実行してみて、
なぜgit pullが失敗して、git fetchが成功したのか気になり、色々調べてみた。

git pullとgit fetchの違いは?

簡単に言うと、git fetch + git merge = git pullのイメージ。

  • git fetch
    リモートリポジトリの最新情報を、リモートリポジトリのアップストリームブランチに反映させる。
    git mergeでアップストリームブランチからローカルリポジトリのローカルブランチを更新する。

  • git pull
    リモートリポジトリの最新情報を、ローカルブランチに反映させる。

アップストリームブランチとは

ローカルブランチが、履歴を追跡するように設定したリモートブランチのこと。

まとめ

git fetch originでリモートリポジトリの最新情報をローカルリポジトリに反映させて、
git reset --hard origin/mainで、リモートリポジトリの内容でローカルリポジトリを上書きしている。

結論で解説した上記の内容を更に詳しく言うと、
リモートリポジトリの最新情報をローカルのアップストリームブランチに反映させて、
そこから、アップストリームブランチ(origin main)の情報を強制的に
ローカルブランチに反映させていた
ということになる。

git pullを実行して、リモートリポジトリの最新情報をローカルブランチに反映させたいがコンフリクトが発生してしまったので、
下記のコマンドでリモートリポジトリの最新情報をアップストリームブランチに反映させたうえで、
ローカルリポジトリをアップストリームブランチの内容に強制的に合わせるということを行う必要があったということが分かった。

$ git fetch origin
$ git reset --hard origin/main
5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4