git pullしたらWarning出たからちゃんと読む。
git pull
をした時、出てきたWarning。
今まで何度か遭遇したけど何とな〜く理解して、とりあえずstash
して対処していました。
しかし、お仕事でこの事象に遭遇した方に、上手く説明することができないことがありました。
この時、自分の理解が合っているのかどうかよりも、上手く説明できない自分に対して、とても悔しかったです。
これがきっかけで、(そのWarningに)いい加減一度ちゃんと向き合わなければ...!と思いました。
ということで!
今回は、その何とな〜く理解して放置していたWarningについて調査して、まとめてみました!!
遭遇したWarning
以下のような画像のWarningが出てくることがあります。
今回は、このWarningについて考えてみたいと思います。
何を言われているのか、どのように対処するのかなど、順を追って見ていきます。
遭遇したときの状況
このWarningに遭遇した状況は以下です。
-
develop
ブランチからfeature/sample_A
ブランチを切る。 -
develop
ブランチで変更を加えてコミット。まだpushはしていない。 -
feature/sample_A
ブランチで変更を加え、コミット・push。 -
feature/sample_A
ブランチを分岐元であるdevelop
ブランチにマージする。 - ローカルの
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
を行うものです。
rebase
がfalse
と指定されていることから、rebase
しないことがわかります。
通常のmerge
と同じ動きをするもので、現在のブランチ(ローカル)が何も変わっていなければfast-forward
を行い、それ以外の場合は、merge commit
を作成してマージします。
fast-forward
とは、現在のブランチの先頭が、マージしてくるブランチの先頭に移動するだけのマージです。現在のブランチとマージしてくるブランチの違いとしては、「マージしてくるブランチで変更を加えた部分」のみです。
また、merge commit
を作成してマージするのは、現在のブランチ・マージしてくるブランチの両方で変更が進んでいる場合です。このような場合には、2つのブランチをまとめる必要があるので、それぞれの変更を取り込んだmerge commit
が作成され、そのコミットが現在のブランチの先頭になります。
merge
は、デフォルトの動作です。
2. rebase
2つ目、rebase
です。
git config pull.rebase true # rebase
こちらは、先ほどと違って、rebase
がtrue
と指定されています。マージではなく、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つの選択肢が用意されていました。
merge
・rebase
・fast-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
Discussion