gitエラー：Updates were rejected because the remote contains work that you do not have locally.


# はじめに

qiita-cli を使って qiita の記事投稿を Github 管理しているのですが、新しい記事を書いて「よし、投稿しよー」と思い、コミット＆プッシュを実施したところ、git のほうで reject（拒否）されました。

エラー内容はこんな感じ

```
$ git push
To github.com:{username}/{repository-name}.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'github.com:{username}/{repository-name}.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```

...なんてこったい。こんなとこでつまづいたらモチベーション下がっちゃうよ。

ということでとりあえず先人たちのエラー解消ノウハウを調査。

# エラー解決方法

エラー内容で検索してヒットした記事を素直に見てみる。

どうやら、リモートリポジトリ（Github）の main ブランチにあって、ローカルの main ブランチにない変更があるみたい。

解決するには、リモートリポジトリから`git pull`でコミットを取得して、差分を解消すればいいらしい。

ということでまずは pull してみる

```
git pull origin main
```

するとこんなメッセージが出た

```
$ git pull origin main
From github.com:{username}/{repository-name}
 * branch            main       -> FETCH_HEAD
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.
```

ふむ、とりあえず Google 翻訳してみる

```
You have divergent branches and need to specify how to reconcile them.
>分岐したブランチがあり、それらを調整する方法を指定する必要があります。

You can do so by running one of the following commands sometime before your next pull:
>これを行うには、次のプルの前に次のコマンドのいずれかを実行します。

git config pull.rebase false  # merge
git config pull.rebase true   # rebase
git config pull.ff only       # fast-forward only

You can replace "git config" with "git config --global" to set a default preference for all repositories.
>「git config」を「git config --global」に置き換えて、すべてのリポジトリのデフォルト設定を設定できます。

You can also pass --rebase, --no-rebase, or --ff-only on the command line to override the configured default per invocation.
>コマンドラインで --rebase、--no-rebase、または --ff-only を渡して、呼び出しごとに構成されたデフォルトをオーバーライドすることもできます。

Need to specify how to reconcile divergent branches.
>分岐したブランチを調整する方法を指定する必要があります。
```

`git pull`コマンドがうまく実行できない状態（リモートとローカルでのコミット差分）だから、対処が必要とのこと。

`git config ~`で`git pull`の挙動設定（3 パターン）をおこなうことで回避できる。（`--global`をつけると、このリポジトリだけじゃなく全体の git のデフォルト設定にも反映できる）

設定変更できなくてもコマンドラインでオプション指定すると、デフォルト設定をオーバーライドして意図した挙動にできる。

こんなことが書いてありますね。

書いてある内容はだいたいわかったけど、git の挙動をあまりカスタマイズしたくないので、今回は「**ローカルの変更を一時退避して、リモートと同期し直してから反映する**」という方法にしようと思います。

## 修正作業

まずはローカルのログを確認

```
git log --oneline
```

結果

```
$ git log --oneline
cc30f73 (HEAD -> main) add article cm03j33di000087n91kurcbfd
1c44383 qiita-cliバージョン更新
9922530 fix tag
```

この`fix tag`の後にリモート側で変更差分がはさまる感じみたい。

ローカルの変更を soft リセット（コミットを取り消すけどファイルの変更はステージングに残る）

```
git reset --soft
```

コミットが消えてステージングに変更差分が出てきた

![VSCodeステージング](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418680/ca2f19ed-0bf9-7ec4-e8fc-09eb63106337.jpeg)

もっかい git のログ確認

```
$ git log --oneline
6287207 (HEAD -> main, origin/main) Updated by qiita-cli
9922530 fix tag
```

リモートの変更が取得できた！

改めてローカルでの変更をコミットしてログ確認してみる

```
$ git log --oneline
45edfcd (HEAD -> main) add article cm03j33di000087n91kurcbfd
660ee2a qiita-cliバージョン更新
6287207 (origin/main) Updated by qiita-cli
9922530 fix tag
```

ふむ、よさそうなので push してみる

```
git push
```

結果

```
$ git push
Enumerating objects: 12, done.
Counting objects: 100% (12/12), done.
Delta compression using up to 10 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 4.28 KiB | 4.28 MiB/s, done.
Total 8 (delta 4), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (4/4), completed with 3 local objects.
To github.com:{username}/{repository-name}.git
   6287207..45edfcd  main -> main
```

よし！できた！

# おわりに

なんとか解消できたけど、そもそも面倒くさがって main ブランチで作業しないで、作業用ブランチ切っておけば簡単に rebase で解決できたなーと反省。

ひとりしか触らないリポジトリだとあるあるな気がするけど、今後はちゃんとやります。

まあポジティブに考えると、git の仕組みに対する理解を深めるいい機会になった。

# 参考

- [git のエラー Updates were rejected because the remote contains work that you do not have locally. 〜the remote changes (e.g., 'git pull ...') before pushing again.の解決法](https://qiita.com/KKDDD/items/b177abf30eebf63cc735)
- [git pull したら Warning 出たからちゃんと読む。](https://zenn.dev/azunasu/articles/92859cb37cbd96)