git stash を戻す方法|pop と apply の違い・コンフリクト対処

開発環境・インフラ
記事内に広告が含まれています。

git stashで作業を退避させたあと、「これ、popとapplyどっちで戻せばいいんだっけ」と手が止まった経験はありませんか。せっかくgit stashで退避させた変更も、戻し方を間違えると、意図しないファイルを上書きしてしまったり、コンフリクトに慌ててしまったりすることがあります。特に、git stashを戻す操作は普段あまり頻繁に使わない分、いざという時に「pop」と「apply」の違いや、戻した後に間違えたときの取り消し方まで正確に覚えている方は多くありません。

この記事では、git stashを戻す際に迷いやすいポイントを、実際に動作するコマンド例とあわせて整理しています。読み終える頃には、状況に応じて自信を持ってstashを戻せるようになるはずです。

この記事を読んでわかること

  • git stash popとapplyの違い、それぞれをどんな場面で使い分ければよいか
  • pop・applyで戻した変更を取り消したいときの安全な対処方法
  • コンフリクトが発生した場合の具体的な解消手順
  • 特定のstashやファイルだけを指定して戻す方法
  • git stash drop・clearで誤って削除してしまったstashを復旧できるかどうか

git stashを戻す基本|まず使うのはpopとapply

git stashで退避させた変更を作業ツリーに戻す方法は、基本的に「git stash pop」と「git stash
apply」の2つです。とりあえず直前のstashをgit stashで戻すだけなら、まずはこの2つのコマンドの使い分けを押さえれば十分です。

git stashを戻す基本|まず使うのはpopとapply

最新のstashを戻すならgit stash pop

直前に退避させたstashを戻したいだけなら、git stash popを実行してください。戻し漏れによる「stashの消し忘れ」を防げるため、単純に元に戻したい場合はpopが基本の選択肢になります。

git stash pop

git stash popは、stashリストの先頭(最新)にあるstashを作業ツリーに適用したうえで、そのstashをリストから削除します。適用と削除がセットになっているコマンドだと理解しておくと、後述するapplyとの違いも整理しやすくなります。

注意点として、適用時にコンフリクトが発生した場合はstashが自動では削除されません。この挙動については後の見出しで詳しく説明します。

stashを残して戻すならgit stash apply

戻した内容を確認してから元のstashを消したい場合や、同じstashを複数のブランチに適用したい場合は、git stash applyを使ってください。popと違ってstashリストに履歴が残るため、戻す操作自体をやり直しやすくなります。

git stash apply

引数を省略した場合は、popと同じく最新のstash(stash@{0})が対象になります。適用後の内容に問題がなければ、必要なタイミングでgit stash dropを実行してstashを手動で削除します。

git stash drop

「戻す操作に一度失敗しても、stashが消えていないので安心してやり直せる」という点が、applyを選ぶ最大の理由です。特に初めて触るリポジトリや、複雑な変更を含むstashを戻す場合は、popより先にapplyを検討する価値があります。

戻す前にgit stash list・showで内容を確認する

git stash 戻すコマンドを実行する前に、git stash listで対象のstashを確認し、git stash showで中身を把握してください。どのstashを戻そうとしているのかを事前に確認することで、意図しないファイルを上書きするミスを防げます。

git stash list

実行結果は次のような形式で表示されます。

stash@{0}: WIP on main: 1a2b3c4 add login form
stash@{1}: WIP on feature/api: 5d6e7f8 update endpoint

特定のstashの変更内容を確認したい場合は、stash@{N}の形式で対象を指定してgit stash showを実行します。

git stash show -p stash@{1}

pオプションを付けると、変更されたファイルの差分(diff)まで表示されます。付けない場合は変更されたファイル名と行数の統計のみが表示されるため、内容までしっかり確認したい場合はpを付けて実行してください。stashが1件しかない場合はstash@{0}を省略できますが、複数ある場合は番号の指定を忘れると意図しないstashを戻してしまうため注意が必要です。

Git - git-stash Documentation

git stash popとapplyの違い・取り消し方

git stashを戻すコマンドとしてpopとapplyのどちらを使うべきか迷ったときは、「戻した後にやり直せるかどうか」を基準に考えると判断しやすくなります。ここでは両者の違いと、戻した後に間違えた場合の取り消し方をまとめて解説します。

git stash popとapplyは何が違う?

結論として、popは「適用+stashの削除」、applyは「適用のみ」という違いがあります。戻し方自体は同じでも、実行後にstashリストへ履歴が残るかどうかが大きく異なります。

比較項目git stash popgit stash apply
変更の適用するする
stashリストからの削除成功時に自動で削除削除されない(手動でdropが必要)
コンフリクト発生時stashは削除されず残る変わらず残る(そもそも削除しない)
同じstashを複数ブランチに適用不向き(1回で消える)向いている
戻した後にやり直したい場合stashが残っていないため復旧がやや手間stashが残っているため再適用しやすい

迷った場合は、まずapplyで戻して内容を確認し、問題がなければgit stash dropで明示的に削除するという流れにすると、誤操作のリスクを減らせます。

git stash apply
# 内容を確認して問題なければ
git stash drop

pop・applyで戻した変更を取り消す方法

git stash popやapplyで戻した変更を取り消したい場合、まずはgit resetではなくgit restoreを使う方法を検討してください。git restoreはファイル単位で作業ツリーやステージング状態を戻せるため、意図しない範囲まで変更を消してしまうリスクがgit reset --hardより低くなります。

作業ツリー上の変更(git add前の状態)を取り消す場合は、次のコマンドを実行します。

git restore .

戻した変更の一部をすでにgit addしていた場合は、先にステージングを解除してから作業ツリーの変更を取り消します。

git restore --staged .
git restore .

特定のファイルだけを対象にしたい場合は、パスを指定して実行してください。

git restore --staged path/to/file.txt
git restore path/to/file.txt

一方、git reset --hard HEADは直前のコミット時点までの変更をまとめて破棄する強力なコマンドです。stashを戻したこと以外に加えた変更もすべて失われるため、pop・apply以降に他の作業を進めていない場合に限定して使うようにしてください。

git reset --hard HEAD

なお、stashによって新規追加されたファイル(untrackedなファイル)はgit restoreやgit reset --hardだけでは削除されません。新規ファイルごと取り消したい場合は、内容を確認したうえでgit cleanを使います。

git clean -n   # 削除対象を事前に確認
git clean -fd  # 未追跡ファイル・ディレクトリを削除

git clean -fは元に戻せない削除操作のため、必ず-nオプションで対象を確認してから実行してください。また、applyで戻した場合はstash自体がリストに残っているため、取り消し後にもう一度git stash applyで戻し直せます。popの場合はstashがリストから削除されているため、やり直す際は後述する「drop・clearで削除したstashを復旧する」方法が必要になることがあります。

git stash popでコンフリクトした場合のstashの扱い

git stash popの実行中にコンフリクトが発生した場合、Gitはstashをリストから自動削除しません。これは、コンフリクトを解消できなかった場合に変更内容を失わないための仕様です。

コンフリクトが起きると、次のようなメッセージが表示されます。

Auto-merging src/app.js
CONFLICT (content): Merge conflict in src/app.js
The stash entry is kept in case you need it again.

メッセージの末尾にある「The stash entry is kept in case you need it again.」の通り、この時点ではstashはまだ削除されていません。git stash listを実行すれば、対象のstashがそのまま残っていることを確認できます。

git stash list

コンフリクトを解消して問題なく作業を進められた場合は、popが自動でstashを削除しなかった分を手動で削除します。

git stash drop

逆にコンフリクト対応をやめて戻す前の状態に戻したい場合は、作業ツリーの変更を取り消したうえで、stashがまだリストに残っていることを確認してください。コンフリクトの具体的な解消手順は後述の「コンフリクトが起きたときの解消手順」で詳しく扱います。

新世代レンタルサーバー『シンレンタルサーバー』

特定のstash・ファイルだけ戻す方法

複数のstashを保存している場合や、stashの中の一部のファイルだけを戻したい場合は、対象を明示的に指定して実行します。ここでは番号指定・ファイル指定・ステージング状態の3パターンに分けて説明します。

stash@{N}を指定して特定のstashを戻す

最新以外のstashを戻したい場合は、git stash listで確認したstash@{N}をコマンドの引数として指定してください。番号を省略すると常に最新のstash(stash@{0})が対象になるため、複数のstashがある状態で番号を省略すると意図しないstashを戻してしまいます。

git stash list
stash@{0}: WIP on main: 1a2b3c4 add login form
stash@{1}: WIP on feature/api: 5d6e7f8 update endpoint

たとえばstash@{1}を戻したい場合は、popでもapplyでも同じ形式で番号を指定します。

git stash pop stash@{1}
git stash apply stash@{1}

popで番号を指定した場合、対象のstashだけがリストから削除され、他のstashの番号は詰めて繰り上がります。番号は固定のIDではなく、常にリストの並び順に対応している点に注意してください。

特定のファイルだけgit restoreで戻す

stashの中身をすべて戻すのではなく、特定のファイルだけを戻したい場合は、git restoreの--sourceオプションでstashを指定します。この方法であればstash自体には手を付けず、対象ファイルの内容だけを作業ツリーに反映できます。

git restore --source=stash@{0} -- path/to/file.txt

複数のファイルを指定したい場合は、パスをスペース区切りで並べます。

git restore --source=stash@{0} -- path/to/file1.txt path/to/file2.txt

同様の操作は従来のgit checkoutでも可能です。git restoreはGit 2.23以降で導入されたコマンドのため、古いGitのバージョンを使っている場合はこちらを利用してください。

git checkout stash@{0} -- path/to/file.txt

この方法で戻した内容はステージング済み(git addされた状態)にはならず、作業ツリー上の変更として反映されます。ステージング状態まで再現したい場合は、次に説明する--indexオプション付きのapply・popを使う必要があります。

stashのステージング状態も戻す方法(–index)

stashを作成する前にgit addしていたファイルのステージング状態まで再現したい場合は、--indexオプションを付けて戻してください。通常のpop・applyでは、stash内でステージング済みだった変更もすべて未ステージングの状態で作業ツリーに展開されます。

git stash pop --index
git stash apply --index

たとえばgit add済みのファイルと未addのファイルが混在した状態でstashを作成していた場合、--indexを付けずに戻すと両方とも未ステージングになりますが、--indexを付けて戻すと元々git addされていたファイルだけがステージング済みの状態で復元されます。ステージングの状態も含めてコミット前の作業を正確に再現したい場合は、通常のpop・applyではなく--index付きのコマンドを使うようにしてください。

なお、--indexでの適用時にステージング内容と作業ツリーの現在の状態が競合している場合、通常のpop・apply以上にコンフリクトが起きやすくなります。コンフリクトが発生した場合の対処は次の見出しで扱います。

git stashを戻すときのトラブルと復旧方法

git stashを戻す操作でつまずきやすいのが、コンフリクトの発生と、誤ってstashを削除してしまった場合の対処です。ここでは実際のトラブルへの対応手順を順番に説明します。

コンフリクトが起きたときの解消手順

コンフリクトが起きた場合は、エラーメッセージの内容を確認したうえで、競合箇所を手動で編集し、解消後に状態を確定させるという流れで対応します。落ち着いて1ファイルずつ処理すれば、通常のマージコンフリクトと同じ手順で解決できます。

たとえばgit stash popの実行時に次のようなメッセージが表示されたとします。

$ git stash pop
Auto-merging src/index.js
CONFLICT (content): Merge conflict in src/index.js
The stash entry is kept in case you need it again.

このメッセージが出た場合は、次の手順で解消します。

  1. git statusを実行し、コンフリクトが発生しているファイルを確認する git status
  2. 対象ファイルを開き、<<<<<<<・=======・>>>>>>>で挟まれた競合箇所を確認しながら、残す内容に手動で編集する
  3. 編集が終わったファイルをgit addでステージングする git add src/index.js
  4. すべての競合を解消したら、popの場合は自動で削除されなかったstashを手動で削除する git stash drop

コンフリクト対応を途中でやめて、stashを戻す前の状態に戻したい場合は、git reset --mergeを使うとコンフリクト状態を解消しつつ作業ツリーを戻す操作前の状態に戻せます。

git reset --merge

この場合、stashはpop・applyのどちらであってもリストに残ったままなので、落ち着いてから改めて戻すことができます。

git stash drop・clearで削除したstashを復旧する

git stash dropやgit stash clearで消してしまったstashは、Gitの内部データが残っていれば復旧できる可能性があります。stashは実体としてはコミットオブジェクトであり、リストから削除されてもGitのオブジェクトデータベースからすぐには消えないためです。

まず、リストから外れたコミットをgit fsckで探します。

git fsck --unreachable --no-reflog | grep commit

出力された中から、該当しそうなコミットハッシュの内容をgit showで確認します。

git show <コミットハッシュ>

目的のstashだと確認できたら、通常のstashと同じようにapplyで作業ツリーに戻せます。

git stash apply <コミットハッシュ>

ただし、この方法はgit gcによって未参照のオブジェクトが実際に削除されるまでの間しか使えません。git gcの実行タイミングはリポジトリの運用によって異なるため、復旧できる保証はない点に注意してください。日常的な対策としては、重要な変更をstashだけに頼らず、こまめにコミットしておくことが最も確実な予防策になります。

戻した変更を安全に破棄するときの注意点

戻した変更を破棄する前には、必ずgit diffやgit statusで現在の変更内容を確認してください。破棄してよい変更かどうかを確認せずにgit reset --hardやgit cleanを実行すると、他の未保存の作業まで巻き込んで失ってしまう可能性があります。

git status
git diff

内容に問題がなければ、前述のgit restoreやgit reset --hardで破棄しますが、破棄する前にもう一度stashとして退避させておくと安全です。

git stash push -m "before-discard-check"

こうしておけば、破棄した後に「やはり必要だった」と気づいた場合でも、退避したstashから内容を確認・復元できます。特にgit clean -fで削除した未追跡ファイルはgit restoreやgit resetでは戻せず、通常は復旧できないため、実行前のgit clean -nによるドライラン確認を省略しないようにしてください。

国内シェアNo.1のエックスサーバーが提供するVPSサーバー『XServer VPS』

よくある質問(FAQ)

stashを作成したときと別のブランチにapplyしても安全ですか?

内容がコンフリクトしなければ問題なく適用できます。stashはブランチの情報を記録していますが、git stash applyやgit stash popはブランチを問わず、現在チェックアウトしているブランチに対して変更を適用する仕組みです。ただし、stash作成時とファイル構成やコードの内容が大きく異なるブランチに適用すると、コンフリクトが発生しやすくなります。適用前にgit stash show -pで差分を確認し、対象ブランチのファイルと大きくかけ離れていないか確認しておくと安心です。

すでにコミットした変更をstashから戻すことはできますか?

git stashはコミットしていない変更(作業ツリーとステージングエリアの差分)を退避させる仕組みのため、すでにコミット済みの変更を戻す場面では通常stashは使いません。コミット済みの変更を取り消したい場合は、git revertで打ち消しのコミットを作成するか、git resetで特定のコミットまで巻き戻す方法を検討してください。

git revert <コミットハッシュ>

stashを作る前にステージングしていた変更は、戻したときどうなりますか?

通常のgit stash pop・git stash applyでは、ステージング済みだったかどうかに関わらず、戻した変更はすべて未ステージングの状態で作業ツリーに反映されます。ステージング状態も含めて元の状態を再現したい場合は、前述の--indexオプションを付けて戻してください。

保存したはずのstashがgit stash listに出てこないのはなぜですか?

考えられる主な原因は2つあります。1つは、別のリポジトリやワークツリーでstashを作成しており、確認しているディレクトリと異なる場合です。stashはリポジトリ単位で管理されるため、リポジトリを移動すると一覧には表示されません。もう1つは、すでにgit stash popやgit stash drop、git stash clearによって削除済みのケースです。削除済みのstashを探す場合は、前述のgit fsck --unreachableによるコミット検索を試してください。

未追跡(untracked)ファイルもstashに含めて戻したい場合はどうすればよいですか?

デフォルトのgit stashは、git addされていない新規ファイル(untrackedファイル)を退避対象に含めません。未追跡ファイルも含めて退避したい場合は、stash作成時に-uオプション(--include-untracked)を付けてください。

git stash push -u

このオプションを付けて作成したstashであれば、git stash popやgit stash applyを実行した際に、未追跡ファイルも含めて作業ツリーに戻されます。

まとめ

git stashを戻す操作は、状況に応じてコマンドを使い分けることが重要です。最後に、この記事で扱った内容を整理します。

  • とりあえず直前のstashを戻すだけならgit stash pop、履歴を残して慎重に戻したいならgit stash applyを使う
  • 戻す前にgit stash listとgit stash showで対象と内容を確認しておくと、意図しないstashを戻すミスを防げる
  • 戻した後に取り消したい場合は、まず安全性の高いgit restoreを検討し、影響範囲を理解したうえでのみgit reset --hardを使う
  • コンフリクトが発生してもstashはすぐには削除されないため、落ち着いてgit statusから競合箇所を確認し、解消後にgit stash dropで片付ける
  • 特定のstashやファイルだけを戻したい場合はstash@{N}の指定やgit restore --source、ステージング状態まで再現したい場合は-indexオプションを使う
  • dropやclearで消してしまったstashも、git gcが実行される前であればgit fsck --unreachableから復旧できる可能性がある

git stash 戻す操作でどのコマンドを選ぶか迷ったときは、まずapplyで安全に確認してからdropするという流れを基本にすると、誤操作によるコード消失のリスクを抑えながら作業を進められます。

WEBCOACH|副業・フリーランス特化型のオンラインWebデザインスクール
タイトルとURLをコピーしました