ローカル変更がある状態でリモート更新と衝突したときの Git マージ手順
ローカルで未コミットのファイルを編集している間に、リモート側へ別のコミットが追加されることがあります。その状態で git pull すると、Git はローカルの変更を上書きする危険があるため、pull を止めることがあります。
この場合は、作業中の変更を git stash で一時退避し、リモート変更を取り込んでから、退避した変更を戻すのが扱いやすい手順です。
この記事では、次のような状況を前提に、確認手順と対応手順を整理します。
- ローカルに未コミット変更がある
- リモートの
origin/mainに新しいコミットが積まれている git pullがローカル変更の上書きリスクで中断された- ローカル変更は消さずに残したい
結論: stash → fetch/merge → stash pop の順で進める
まず結論です。
未コミット変更がある状態でリモートの更新を取り込みたい場合は、次の順で作業します。
# 実行場所: 対象リポジトリのルートディレクトリ
# 対象: Git 管理下の作業ツリー
git status
git stash
git fetch origin
git merge origin/main
git stash pop
git status
この手順では、ローカルの作業内容を一時的に退避してから、リモートの変更を取り込みます。その後、退避していた作業内容を現在のブランチへ戻します。
ここがポイント:
git pullは内部的にはおおむねfetchとmergeの組み合わせです。未コミット変更が邪魔になる場合は、先にstashで作業ツリーをきれいにしてから、同じ流れを分解して実行します。
前提条件
ここでは、次の状態を想定します。
- ブランチ:
main - リモート:
origin/main - ローカル: 未コミット変更あり
- リモート: ローカルより先に進んでいる
- 目的: ローカル変更を残したまま、リモート変更を取り込む
たとえば git status で、次のような表示が出ている状態です。
Your branch is behind 'origin/main' by 13 commits, and can be fast-forwarded.
Changes not staged for commit:
modified: src/wp_post_tool/webapp.py
modified: src/wp_post_tool/web_templates/post_edit.html
modified: src/wp_post_tool/web_static/app.css
この表示から分かることは2つあります。
- ローカルブランチは
origin/mainより 13 コミット遅れている - 3つのファイルに未コミット変更がある
このまま git pull すると、Git はリモート変更の取り込みによってローカルの未コミット変更が壊れる可能性を検知し、処理を止めることがあります。
困っていること: pull したいが未コミット変更を消したくない
この場面で避けたいのは、作業中の変更を失うことです。
特に、次のような状況では慎重に進める必要があります。
- まだコミットできるほど作業がまとまっていない
- 変更内容を一度確認してからコミットしたい
- リモートの変更も早めに取り込みたい
- 同じファイルを別環境や別作業者も触っている可能性がある
git pull が止まるのは不便ですが、Git の挙動としては安全側です。未コミット変更を勝手に上書きせず、ユーザーに判断を促している状態と考えると分かりやすいです。
確認手順
作業前に、現在の状態を確認します。
1. 作業ツリーの状態を見る
# 実行場所: 対象リポジトリのルートディレクトリ
git status
見るポイントは次の通りです。
- どのブランチにいるか
origin/mainより遅れているか- 未コミット変更があるか
- 変更ファイルがどれか
- untracked file があるか
git stash は通常、追跡済みファイルの変更を退避します。新規作成した未追跡ファイルも含めて退避したい場合は、後述する git stash -u を検討します。
2. 退避前に差分を確認する
作業内容を退避する前に、何を変更していたかを確認します。
# 実行場所: 対象リポジトリのルートディレクトリ
git diff
ステージ済みの変更がある場合は、次も確認します。
git diff --cached
この確認を挟むと、stash pop 後にコンフリクトが起きた場合でも、元の意図を追いやすくなります。
対応手順
ここから実際の対応です。
ステップ1: ローカル変更を一時退避する
# 実行場所: 対象リポジトリのルートディレクトリ
git stash
これで、作業中の変更が stash に積まれ、ワーキングツリーはクリーンな状態に戻ります。
退避できたか確認します。
git status
git stash list
git stash list で stash@{0} のような項目が表示されれば、退避されています。
未追跡ファイルも退避したい場合は、通常の git stash ではなく次を使います。
git stash -u
ただし、退避対象が増えるため、実行前に git status で含まれるファイルを確認しておくと安全です。
ステップ2: リモートの変更を取得する
# 実行場所: 対象リポジトリのルートディレクトリ
git fetch origin
fetch は、リモートの最新情報を取得します。この時点では、まだ現在のブランチには統合しません。
続けて origin/main を現在のブランチへ統合します。
git merge origin/main
ローカルに独自コミットがなく、単にリモート側だけが進んでいる場合は、fast-forward で進みます。fast-forward では新しいマージコミットを作らず、ローカルのブランチ位置だけが origin/main に追いつきます。
ステップ3: 退避していた変更を戻す
# 実行場所: 対象リポジトリのルートディレクトリ
git stash pop
stash pop は、最新の stash を現在の作業ツリーへ再適用し、成功すれば stash から削除します。
変更箇所がリモート変更と重ならなければ、自動で戻ります。重なる場合は、対象ファイルにコンフリクトマーカーが入ります。
コンフリクトが起きた場合は、次の流れで対応します。
git status
# コンフリクトしたファイルを編集して解消
git add <解消したファイル>
git status
作業内容として保存する段階になったら、通常通りコミットします。
git commit -m "リモート更新取り込み後のローカル変更を反映"
なぜこの方法で解決できるのか
git pull は、リモートの変更取得と現在ブランチへの統合をまとめて実行します。作業ツリーに未コミット変更があると、統合時にその変更が上書きされる可能性があります。
Git はその危険があると判断すると、処理を止めます。
stash を使うと、次のように作業を分けられます。
- 未コミット変更を一時退避する
- 作業ツリーをクリーンにする
- リモート変更を取り込む
- 退避した変更を戻す
- 必要ならコンフリクトを解消する
つまり、ローカル変更を保持したまま、リモート変更を先に取り込める状態を作るのがこの手順の目的です。
代替案と使い分け
状況によっては、stash → merge → pop 以外の選択肢もあります。
| 状況 | 候補 | 向いているケース |
|---|---|---|
| 未コミット変更がある | git stash | 作業途中で、まだコミットしたくない場合 |
| ローカル変更がまとまっている | git commit してから merge | 変更単位として残せる状態になっている場合 |
| ローカルにも独自コミットがある | git rebase | 履歴を一直線に保ちたい運用の場合 |
| 退避した変更が不要になった | git stash drop | 戻す必要がないと確認できた場合 |
rebase は履歴を整理しやすい一方で、共有済みコミットに対して不用意に使うと混乱の原因になります。チーム運用では、ブランチ運用ルールに合わせて選びます。
よく使うコマンド
この場面で使うコマンドをまとめます。
# 作業状態を確認
git status
# 未ステージの差分を確認
git diff
# ステージ済み差分を確認
git diff --cached
# 作業中の変更を退避
git stash
# 未追跡ファイルも含めて退避
git stash -u
# stash の一覧を確認
git stash list
# 最新の stash を戻す
git stash pop
# 最新の stash を削除
git stash drop
# リモート情報を取得
git fetch origin
# origin/main を現在のブランチに統合
git merge origin/main
git stash drop は、退避した変更を破棄します。戻す必要がないと確認してから実行します。
再発防止と次回の確認ポイント
同じ状況は、複数人で同じリポジトリを触る環境ではよく起きます。完全に避けるというより、作業前後の確認を習慣化するのが現実的です。
次回は、作業開始前と pull 前に次を確認します。
git statusで未コミット変更を確認するgit fetch originでリモートの進み具合を確認する- 変更が大きい場合は、先に小さくコミットできないか考える
- 未追跡ファイルがある場合は、
git stash -uが必要か確認する stash pop後は必ずgit statusを見る- コンフリクトが出たら、マーカーを消してから
git addする
特に stash は便利ですが、積みっぱなしにすると後から中身を思い出しにくくなります。退避したら、戻すか、不要なら破棄するところまで確認した方が安全です。
まとめ
ローカルに未コミット変更があり、リモート側にも新しいコミットがある場合は、いきなり git pull で進めようとすると止まることがあります。
基本手順は次の通りです。
git statusで状態を確認するgit stashでローカル変更を一時退避するgit fetch originでリモート情報を取得するgit merge origin/mainでリモート変更を取り込むgit stash popでローカル変更を戻す- コンフリクトがあれば解消する
判断基準はシンプルです。まだコミットしたくない作業中の変更があるなら stash、変更がまとまっているなら先にコミットです。
次に同じエラーが出たときは、まず git status を見て、「未コミット変更」と「リモートとの差分」のどちらが問題になっているかを切り分けるところから始めると、手順を誤りにくくなります。

コメント