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

# 今回の課題
下記のコマンドで、
リモートリポジトリに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`で、アップストリームブランチの内容を強制的にローカルリポジトリを上書きしている。

**◼︎参考記事**

https://wonderhorn.net/programming/pullunmerged.html


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

まず、[今回の課題](https://qiita.com/Ayumu-y/items/7fb229f624d458ddacd1#%E4%BB%8A%E5%9B%9E%E3%81%AE%E8%AA%B2%E9%A1%8C)に記載したエラーで、pullをするように指示があったので、pullをしてみた。
```
$ git pull origin [リモートリポジトリのURL]
```
すると、下記のように「関連性のない履歴のマージができない」というエラーが発生した。
ローカルリポジトリとリモートリポジトリの変更履歴が異なっているため、エラーが発生してしまった様子。
```terminal
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を試しても、もちろん最初と同じエラーが発生してしまう...。



<font color="red">最後に下記を試してからgit pushをしてもエラーが発生しなくなった！<font>
```
$ 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`で、リモートリポジトリの内容でローカルリポジトリを上書きしている。

[結論](https://qiita.com/Ayumu-y/items/7fb229f624d458ddacd1#%E7%B5%90%E8%AB%96)で解説した上記の内容を更に詳しく言うと、
**リモートリポジトリの最新情報をローカルのアップストリームブランチに反映させて、
そこから、アップストリームブランチ(origin main)の情報を<font color="red">強制的に**<font>**ローカルブランチに反映させていた**。
ということになる。

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