開発ブログ

WWWクリエイターズが送る、Git、CSS、HTML、コマンドライン、Macの便利機能など、開発に関する役立ち情報発信します。気まぐれに更新。

git pullでローカルをリモートで強制上書きする方法、まとめ。

最終更新:2017-07-04 by Joe

git pull して、リモートブランチの最新に合わせようとしたら・・、あれ?コンフリクト・・?なにこれ、うまくいかない!「git push -f origin masterして強制Pushはできたのに。git pull -f origin master的な強制コマンドはないの?!」

とにかくリモートに合わせたい。そんなあなたのための、解決方法と解説です。

git pullを強制する方法

まずはコマンドの紹介からです。masterブランチでの操作を例にしますね。

ローカルのmasterを、強制的にリモートのmasterに合わせる

「pullの強制」というよりは、要は「reset」という方が正しいですね。

もちろん、git reset --hardは、手元にある作業ツリーとインデックスの変更内容は、すべてふっとんで消えてなくなりますので、実行前は注意して慎重に行って下さい。

一般的にgitでは、「コミットされていない変更」は、一度失うともう帰ってこないですので、不安な人は必ず実行前に、git statusして、作業ツリーの状態を確認して下さい。もし、作業ツリーとインデックスを別の場所に退避しておきたかったら「git stash」などがあります。

git pull について、おさらい

前提知識として、gitで「pull」というのは「fetch して、mergeする」を立て続けに行うためのコマンドでした。「pushの反対だからpull」って感じで名前が付けられたと思うのですが、実際の動作が必ずしもきっちり対象になっていない点が、若干初学者の混乱のもとになっている気もします。

すなわち、いつものpullコマンドは、

上記は、この2つのコマンドのショートハンドです。

※「FETCH_HEAD」は、要は「origin/master」がマージされると解釈すれば問題無いです。fetch実行時、その後のマージ実行のため、取得したリモート側のブランチ名(refs)とコミット名との対を、.git/FETCH_HEADに記述します(これはgitユーザは意識する必要はありません)

git fetch origin mater について

「git fetch origin master」は、リモートレポジトリ「origin」にあるブランチ「master」を、ローカルのリモート追跡ブランチに反映させる。という意味のコマンドです。

リモート追跡ブランチ・・?

「リモート追跡ブランチ」と聞いて「えーと、なんだっけ・・・」の人は、gitのリモートの概念をへの理解が浅い可能性がありますので、こちらも補足しておきます。

下記のコマンドを打てば、すべてのローカルブランチが表示されますが・・

一度でもoriginをfetchしたことのあるローカルレポジトリ環境では、おそらくアウトプットは、のように表示するはずです。

この「remotes/xxxx/xxxx」となっているブランチ名が、すなわち「リモート追跡ブランチ」です。

これはローカルにあるブランチの一種ですが、通常あなたがコミットを行う類のブランチではなく、常に対応するリモートブランチからfetch して更新される対象とするためのブランチとして区別されています。

gitマニュアルでは「A remote tracking branch」とされていますので「リモートトラッキングブランチ」とそのまま呼んだりもします。リモート追跡ブランチは、通常のローカルブランチのようにチェックアウトして作業する事はできません。

ちなみに、git push 成功時には、(上流ブランチとして設定されていれば)自動的に対応する追跡ブランチの参照が更新されます。

もし上流ブランチが設定されていない場合は「git push -u origin master」などのuオプションで設定できます。

git merge origin/master について

fetchしたら、あとはmergeです。

mergeコマンドにおいて、リモート追跡ブランチを指定することができます。

「git merge origin/master」は『「origin」という名前のリモートレポジトリ上にあるブランチ「master」の追跡ブランチ、すなわち「origin/master」を現在のブランチにマージする』という意味です。

git pullの失敗理由と、その解決

git pull origin materが失敗しているときは、おそらく origin/master → master のマージがコンフリクトしているときが多いはずです。

普通のチームの開発では、リモートのブランチを「正」とする事がほとんどだと思いますので、ローカルと噛み合わない場合「あ〜、めんどくさいからずぱっと強制したい・・」となるわけです。

git mergeを強制する

git mergeがコンフリクトする時は、コンフリクトを解決するのが教科書通りですが、もし完全に origin/master 側が「正」としているのであれば、「git merge --theirs」などというコマンドもありますが、そもそもマージによって、新しいコミットが作られてしまうので、これは選択肢ではありません。

ここでは、より強力な強制力を持つ「git reset 」を利用して、強制的に一致させます。

一撃必殺、git reset --hard

現在のブランチの状態を「強制的に」他のブランチの状態に合わせるときの方法として、「git reset --hard 」があります。reset --hard は、現在のブランチの状態を強制的に対象に合わせるコマンドでしたね。

resetコマンドは3種類が代表的です。

git resetのモード

コマンドとオプション 動作
git reset --soft 現在のbranchの先頭 だけをリセット
git reset
git reset --mixed
現在のbranchの先頭と、インデックスをリセット
git reset --hard 現在のbranchの先頭、インデックスと作業ツリーを全部リセット

以上です。

うまくgit pull を強制(?)できたでしょうか。


ローカルの変更を保存しつつ、リモートの最新に強制的に合わせる

おまけです。

上記の方法では、git reset --hard により、ワーキングツリーの状態を完全に破棄してしまいます。もし、破棄しないでおいてあとで確かめたり、変更内容を利用したい時、別途、残しておくことができます。

ローカルの変更を保持しつつ、リモートで強制上書き

これまでのmasterブランチを名前を変え、新しくmasterブランチを作成します。(4)の時点で、自動的にリモート追跡ブランチ「origin/master」を起点にして新しいmasterブランチが生成されます。(指定されたブランチ名がリモートトラッキングブランチに見つかったときのgitによる補助的な振る舞いです)

さておき、たぶんこんなかんじになるはずです。

これで、自分のローカル変更を別の名前で保存できたことになります。

ともすれば、「自分の実の子であるmasterちゃんを戸籍変更して、別の女との間に新しくできた子に、前の子の名前をつけて、その子として育てる」という、なんだか推理サスペンス的な操作にも見えます。一抹の後ろめたさを感じてしまいます。

もちろん、コミットを作らなくても、git stashを使っても大丈夫です。でも、ブランチにしたほうが、なんだかクリーンで、管理しやすかったりもします。そのへんは好みや状況に応じてどうぞ。

以上です。

git pull強制に関する関連情報

リモートのブランチや、リモートトラキングブランチとローカルとの操作は、最初慣れるまで戸惑う事が多いです。こちらの記事も思い当たる方は是非どうぞ。