🚨

git pullしたらWarning出たからちゃんと読む。

2023/12/09に公開

git pullをした時、出てきたWarning。
今まで何度か遭遇したけど何とな〜く理解して、とりあえずstashして対処していました。

しかし、お仕事でこの事象に遭遇した方に、上手く説明することができないことがありました。
この時、自分の理解が合っているのかどうかよりも、上手く説明できない自分に対して、とても悔しかったです。
これがきっかけで、(そのWarningに)いい加減一度ちゃんと向き合わなければ...!と思いました。

ということで!
今回は、その何とな〜く理解して放置していたWarningについて調査して、まとめてみました!!

遭遇したWarning

以下のような画像のWarningが出てくることがあります。
今回は、このWarningについて考えてみたいと思います。

何を言われているのか、どのように対処するのかなど、順を追って見ていきます。

遭遇したときの状況

このWarningに遭遇した状況は以下です。

  1. developブランチからfeature/sample_Aブランチを切る。
  2. developブランチで変更を加えてコミット。まだpushはしていない。
  3. feature/sample_Aブランチで変更を加え、コミット・push。
  4. feature/sample_Aブランチを分岐元であるdevelopブランチにマージする。
  5. ローカルのdevelopブランチを最新状態にするため、git pullする。(リモートブランチの状態を反映する。)

すると、先ほどのようなWarningが出てきます。
git pullしたときに出てきました。

変更の状態はこんな感じです。

左下あたりの赤丸部分を見てみると、リモートブランチからpullしてくる変更が2件、リモートブランチにpushする変更が1件あることがわかります。

Warningを読んでいく!

それでは、このWarningを解消する方法を探るため、Warningメッセージを解読していきます。
hintと書かれていますし、何か教えてくれているっぽいことはわかると思います。

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.

まずは1行目から。

まずは1行目を解読していきます。

hint: You have divergent branches and need to specify how to reconcile them.

ちょっと雑な訳ですが、「不一致なブランチがあるので、それらを調整する方法を指定する必要がある」と言われているのかなと想定できます。

英単語の参考資料としては以下になります。
(英語教材で有名なアルクさんの英辞郎です。)
divergentとは
reconcileとは

不一致なブランチってどういうこと?

「不一致なブランチ」と言われている理由はなぜなのでしょうか?

まず、何と何を比較して「不一致だ、異なる」と言っているのか考えてみましょう。
これは、git pullでリモートブランチの変更を取り込む際に起こっていることから、「リモートブランチ」と「ローカルブランチ」を比較しています。

git pullは、リモートブランチの状態をfetchして(取得して)きて、ローカルブランチへのマージ(反映)を行うコマンドです。
つまり、リモートブランチから変更を取り込もうとpullしてみたけど、ローカルでリモートに反映されていない変更が加えられているので、どう対応するのかを指定する必要があるのです。git pull自体は、コンフリクトや差分を解消するところまではやってくれません。
「リモートからの変更を取り入れる時点で、ローカルでも新たに変更されていること」が悪い・間違っている訳ではなく、対応方法を確認されているだけなのです。

これは、このWarningが出るようになった理由とも関係があると思いますが、このような場合において、デフォルトのmergeで対応したい人だけでなく、コミットを作らずにrebaseで対応したい人もいます。そういった場合に、rebaseの指定を忘れて(その人にとって)不要なコミットが作られないようにするため、このWarningが出るようになったようです。
(Warningが出るようになったのは、Gitのv2.27.0からです。)

2〜3行目を解読してみる。

次に、2〜3行目です。

hint: You can do so by running one of the following commands sometime before
hint: your next pull:

1行目で、リモートブランチとローカルブランチの差異を調整する方法を指定するように言われていることが推測できました。
2〜3行目では、その方法をどうやって指定したらよいのか、教えてくれています。
ざっくり、以下のようなことを言っています。
「次回pullする前に、次のコマンドのうちどれか1つを実行することで(差異を解決する方法を指定することが)できます。

「次のコマンド」って何?

じゃあ、「次のコマンド」って何?ってなりますよね。
それが、5〜7行目の3つのコマンドのことを指します。
3つとも、git configで設定を行うためのコマンドです。

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

それぞれがどういう方法なのか、簡単に説明します。

1. merge

まずは1つ目、mergeです。

git config pull.rebase false  # merge

これは、git pullしてくるときに、rebaseせずにmergeを行うものです。
rebasefalseと指定されていることから、rebaseしないことがわかります。

通常のmergeと同じ動きをするもので、現在のブランチ(ローカル)が何も変わっていなければfast-forwardを行い、それ以外の場合は、merge commitを作成してマージします。

fast-forwardとは、現在のブランチの先頭が、マージしてくるブランチの先頭に移動するだけのマージです。現在のブランチとマージしてくるブランチの違いとしては、「マージしてくるブランチで変更を加えた部分」のみです。

また、merge commitを作成してマージするのは、現在のブランチ・マージしてくるブランチの両方で変更が進んでいる場合です。このような場合には、2つのブランチをまとめる必要があるので、それぞれの変更を取り込んだmerge commitが作成され、そのコミットが現在のブランチの先頭になります。

mergeは、デフォルトの動作です。

2. rebase

2つ目、rebaseです。

git config pull.rebase true   # rebase

こちらは、先ほどと違って、rebasetrueと指定されています。マージではなく、rebaseを行う方法です。
このrebaseは、fetchしてきた変更(リモート)を現在のブランチ(ローカル)に適用し、現在のブランチの変更をその後につなげて、コミット履歴をまとめます。必要があれば、コンフリクト解消を行います。

3. fast-forward only

最後、3つ目。fast-forward onlyです。

git config pull.ff only       # fast-forward only

この方法は、fast-forwardができる場合のみ実行し、できない場合はエラーを返して終了します。
現在のブランチとマージしてくるブランチでそれぞれ変更が進んでいる場合は、fast-forwardできない場合にあたります。

これで、「状態が異なるブランチを調整する方法」がわかり、これら3つのうちどれかを設定すれば良いことがわかりました。

9〜12行目

ここまでで、このWarningを解消するために何をすれば良いと言ってくれているのか、わかってきました。
9〜12行目は一気に解読します。

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.

先ほど、3つのコマンドが出てきましたが、それらは、git configでこのプロジェクトで使うgitの設定を指定するものでした。でも、全てのリポジトリで同じ設定にしたい場合もあるかもしれません。そういう場合には、git configのところをgit config --globalに置き換えて実行しましょうと教えてくれています。
また、--rebase--no-rebase--ff-onlyを指定して実行することで、設定を無効にして、指定した方法で実行することもできるとのことです。

最後の1行

ついにやってきました、最後の1行!

fatal: Need to specify how to reconcile divergent branches.

ここまで読んできた皆さんにはもうわかると思いますが、最初の1行目に書かれていたものと同じ内容の文章です。

細かくメッセージを解読していき、やっと何を言われていたのか、どう解消するのかがわかりました。
ここまで解読に付き合って下さった皆さん、お疲れ様です!!

対応する!

それでは、メッセージの解読ができたので、Warning解消までやっていきましょう。

メッセージにおいて、3つの選択肢が用意されていました。
mergerebasefast-forwardの3つでした。

チームの中で統一しているものがあればそれに合わせる必要がありますし、何もないのであれば、デフォルト動作のmergeを選んでおくのが良いのかなと思っています。

参考として、mergeの場合とrebaseの場合、それぞれ検証してみます。

mergeの場合

mergeすると、merge commitが作られていることがわかります。(git pull --no-rebaseで再現しました。)

rebaseの場合

rebaseすると、merge commitは作られず、ローカルのコミットに取り込んだ変更が含まれます。(git pull --rebaseで再現しました。)

コミットの中身をみるとこんな感じ。

ちなみに、もしgit configで設定したくないという場合。自分は、ローカルからpushしようとしている変更をgit stash -uで一旦退避してローカルを元の状態に戻し、先にgit pullを実行してから戻すようにすれば対応していました。

おわりに

お読みくださり、ありがとうございます!!

今まで、何とな〜く、「リモートから変更を取り入れようとしているのに、ローカルでも変更をコミットしてるから出てきてるんやなー」と認識していました。ふわっとしか理解しておらず、「なんかconfig設定せなあかんし、他で影響出たりしたら面倒やし、とりあえずstashしとこ...」みたいに考えてました。
長らく放置してしまいましたが、今回やっと理解を少し進めることができました🎉

記事の内容に不備などございましたら、コメントでご教示頂けますと嬉しいです。

参考資料

Git 2.27.0 から git pull をすると表示されるようになった "Pulling without specifying how to reconcile divergent branches is discouraged." について
git pullするとhintがたくさん出てくる
pull: warn if the user didn't say whether to rebase or to merge
git pull と git pull –rebase の違いって?図を交えて説明します!
サル先生のGit入門 pull
サル先生のGit入門 ブランチの統合
サル先生のGit入門 7. rebaseでマージする
git git-pull
git git-merge
git git-rebase

GitHubで編集を提案

Discussion