今回の課題
下記のコマンドで、
リモートリポジトリに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