-uで退避し、--indexで戻してから消す
コミットしていない変更を一時的に外して、作業フォルダーを最後のコミットと同じ状態にするのがgit stashです。新しく作ってまだaddしていないファイル(未追跡ファイル)も一緒に外すには-uを付け、後で見分けられるよう-mでメッセージを付けます。
戻すときは、git stash listで自分のメッセージの行を確かめてからgit stash apply --indexを実行します。--indexを付けると、add済みだった変更がステージ済みの状態で戻ります。この記事ではpopではなくapplyを使い、git status --shortで戻ったことを確かめてからgit stash dropで一覧から消します。popは戻すと同時に一覧から消すので、戻った内容を確かめる前に一覧から消えます(衝突したときは消えずに残ります)。
以下のstash@{0}は、一覧の最新の1件を指します。退避を重ねると番号はずれるため、実行の直前にgit stash listを見て番号を決めてください。この記事のコマンドはBash(WSLやGit Bashなど)用です。PowerShellでは{}が特別な意味を持つため、stash@{0}を'stash@{0}'のように引用符で囲んでください。
git stash push -u -m 'draft notes'
git status --short
# ここで別の作業をする
git stash list
git stash apply --index stash@{0}
git status --short
git stash drop stash@{0}-uと--indexを付けない場合に残るもの・戻らないもの
オプションなしのgit stash(git stash pushと同じ)が退避するのは、Gitが追跡しているファイルの変更だけです。未追跡ファイルは作業フォルダーに残ったままで、別のブランチへ切り替えても付いていきます(切り替え先に同じ名前の追跡ファイルがあると、git switchは止まります)。.gitignoreで無視しているファイルは-uでも退避されず、退避するには-a(--all)が必要です。
add済みの変更は退避されますが、--indexを付けずにapplyやpopで戻すと、変更の中身は戻ってもステージからは外れた状態になります。どの変更をaddしていたかを覚えていない場合は、--indexを付けて戻してください。
表は横にスクロールできます →
| 変更の種類 | git stash push(オプションなし) | -uを付けた場合 |
|---|---|---|
| 追跡中のファイルの変更(add済み・未addとも) | 退避される | 退避される |
| 未追跡のファイル | 退避されず、作業フォルダーに残る | 退避され、作業フォルダーから消える |
| .gitignoreで無視しているファイル | 退避されない | 退避されない(-aで対象になる) |
練習用フォルダーを作り、そこへ移動する
以下はGitが使えるBash(WSLやGit Bashなど)用です。PowerShellへそのまま貼る例ではありません。実務のリポジトリではなく、まだ存在しないgit-stash-practiceというフォルダーで試します。次の2行は1行ずつ実行し、エラーが出たらそこで止めてください。既に同名フォルダーがある場合は、別の新しい名前を選びます。
mkdirとcdの両方が成功したことを確かめてから、次へ進みます。
mkdir git-stash-practice
cd git-stash-practice3種類の途中の変更を作る
note.txtとtodo.txtを最初にコミットし、その後で3種類の変更を作ります。note.txtは編集してadd済み、todo.txtは編集だけ、memo.txtは新しく作っただけ(未追跡)です。名前とメールアドレスは、この練習リポジトリ内だけに設定する例示値です。リモートへの接続や送信は行いません。git init -bはGit 2.28以降で使えます。それより前の版では-b mainを外して実行し、以降の表示のmainを自分のブランチ名に読み替えてください。
最後のgit status --shortは、M note.txt(左列のMはステージ済み)、 M todo.txt(右列のMは未ステージ)、?? memo.txt(未追跡)の3行になります。
git init -b main
git config user.name 'Practice'
git config user.email 'practice@example.invalid'
printf 'base\n' > note.txt
printf 'todo 1\n' > todo.txt
git add -- note.txt todo.txt
git commit -m 'Base files'
printf 'draft 1\n' >> note.txt
git add -- note.txt
printf 'todo 2\n' >> todo.txt
printf 'memo\n' > memo.txt
git status --short-uとメッセージを付けて退避する
git stash push -u -m 'draft notes'を実行すると、3つの変更がすべて外れ、git status --shortは何も表示しなくなります。git stash listにはstash@{0}: On main: draft notesの1行が出ます。Onの後ろは退避したときのブランチ名です。
退避した中身はgit stash showで見られますが、オプションなしでは未追跡のmemo.txtが一覧に出ません。この練習では、--include-untrackedを付けた2つ目のコマンドで、memo.txt・note.txt・todo.txtの3ファイルが表示されます。
git stash push -u -m 'draft notes'
git status --short
git stash list
git stash show stash@{0}
git stash show --include-untracked stash@{0}退避している間に、別の修正をコミットする
作業フォルダーが最後のコミットと同じ状態になったので、急ぎの修正だけをコミットできます。この練習では、退避した変更とは別のファイルfix.txtを追加します。退避した内容はこのコミットに含まれません。
printf 'fix\n' > fix.txt
git add -- fix.txt
git commit -m 'Urgent fix'
git log --oneline--indexで戻し、確かめてからdropする
git stash listでdraft notesの行がstash@{0}であることを確かめてから、git stash apply --index stash@{0}を実行します。git status --shortは退避する前と同じ3行(左列にMのnote.txt、右列にMのtodo.txt、?? memo.txt)になります。
戻ったことを確かめたら、git stash drop stash@{0}で一覧から消します。Dropped stash@{0}の後ろの括弧に、消したstashのIDが表示されます。誤って消したときに使うため、すぐに画面を閉じないでください。最後のgit stash listは何も表示しません。
--indexを付けずにgit stash apply stash@{0}で戻すと、この練習ではnote.txtのMが右列に移り、add済みだった変更がステージから外れます。
git stash list
git stash apply --index stash@{0}
git status --short
git stash drop stash@{0}
git stash listpopが衝突したら、stashは一覧に残る
退避している間に、同じファイルの同じ場所を別のコミットで変えていると、戻すときに衝突します。下の例は、退避した変更とコミットした変更がnote.txtの末尾に別々の行を足す場合です。先に、ここまでの変更をコミットして片付けます。
git stash popを実行するとCONFLICTと表示され、終了コードは1になります。最後にThe stash entry is kept in case you need it again.と表示され、git stash listにはnote editの行が残ります。git status --shortはUU note.txtで、note.txtには<<<<<<< Updated upstreamから>>>>>>> Stashed changesまでの印が入ります。
--indexを付けて戻す場合も、衝突すると失敗することがあります。Git公式の説明では、衝突の情報がステージに記録されるため、add済みだった状態をそのまま戻せなくなります。
git add -A
git commit -m 'Save draft'
printf 'stash line\n' >> note.txt
git stash push -m 'note edit'
printf 'committed line\n' >> note.txt
git commit -am 'Other edit'
git stash pop
git stash list
git status --short
cat note.txt衝突を直してから、残ったstashを消す
印の行を消して、残したい内容だけにnote.txtを書き直します。この練習では、コミット済みのcommitted lineと退避していたstash lineの両方を残します。git add -- note.txtで解決済みにすると、git status --shortはnote.txtの左列にMが付いた1行になります(ステージ済み)。
popは衝突したときにstashを消さないので、内容が正しく戻ったことを確かめてから、自分でgit stash dropを実行します。消さないままにすると、次にpopしたときに同じ変更をもう一度当てることになります。最後に解決した内容をコミットし、git status --shortが何も表示しないことを確かめます。
退避した後でブランチが大きく変わり、衝突が多い場合は、git stash branch 新しいブランチ名 stash@{0}で、退避したときのコミットから新しいブランチを作って戻す方法もあります。Git公式の説明では、退避したときのコミットの上に戻すため衝突しません。成功するとそのstashは一覧から自動で消えるので、続けてgit stash dropを実行しないでください(実行すると、繰り上がった別のstashを消します)。
printf 'base\ndraft 1\ncommitted line\nstash line\n' > note.txt
git add -- note.txt
git status --short
git stash list
git stash drop stash@{0}
git stash list
git commit -m 'Keep both lines'
git status --short誤ってdropしたら、IDで戻す
dropしたstashは、git stash listから消えた後も、git gcで削除されるまでは中身がリポジトリに残ります。dropしたときに表示されたIDが分かっていれば、git stash apply IDで戻せます。
IDが分からない場合、Git公式の説明はgit fsck --unreachableで一覧から外れたstashを探す方法を示しています。ただし、例にある--grep=WIPは、件名にWIPを含むstashを探します。メッセージを付けずに退避した件名はWIP on ブランチ名ですが、-mでメッセージを付けると件名はOn ブランチ名: メッセージになり、この練習では--grep=WIPのままでは何も表示されませんでした。自分で付けたメッセージで探します。
下の例は、前の節までの変更をすべてコミットした状態から、lost workというメッセージで退避したstashをdropし、件名から探して戻します。$(...)は、中のコマンドの出力をlost_idに入れる書き方です。まとめて貼り付けず1行ずつ実行し、途中のechoで40桁のIDが1行だけ表示されることを確かめてからapplyへ進みます。applyは途中でAlready up to date.と表示しますが、エラーではありません。最後のgit status --shortが?? lost.txtになれば戻っています。2行以上出たら、git log --merges --no-walkの--format=%Hを%h %ad %sに変えて件名と日時を見比べ、戻すIDを決めてください。
到達できなくなったstashは、git gcで削除されると戻せません。git gcの既定では、到達できないオブジェクトのうち2週間より古いものが削除の対象になります。この2週間はdropした日ではなく、stashを作ったときから数えます。git gcは他のコマンドの後に自動で実行されることもあるため、誤ってdropしたと気付いたらすぐに探してください。git stash clearで全部消した場合も同じ方法で探せますが、Git公式は戻せないことがあると説明しています。
printf 'lost\n' > lost.txt
git stash push -u -m 'lost work'
git stash drop
lost_id=$(git fsck --unreachable | grep commit | cut -d' ' -f3 | xargs git log --merges --no-walk --grep='lost work' --format=%H)
echo "$lost_id"
git stash apply "$lost_id"
git status --shortworktreeを使うと、stashの一覧は共有される
git worktreeで同じリポジトリの作業フォルダーを複数使っている場合、stashの一覧はすべての作業フォルダーで共通です。Git公式のworktreeの説明では、refs/で始まる参照は(refs/bisect・refs/worktree・refs/rewrittenを除いて)共有され、stashの最新はrefs/stashに記録されます。
練習用のリポジトリでworktreeを1つ追加し、そちらでotherというブランチからstashを作ると、元の作業フォルダーのgit stash listの先頭にstash@{0}: On other: from wt2が出ました。別の作業フォルダーで退避した直後は、stash@{0}が自分の退避ではありません。-mでメッセージを付け、git stash listでブランチ名とメッセージを確かめてから番号を指定してください。
長く置くならコミットにする
stashはブランチではないため、通常のgit pushではリモートへ送られません。数日以上置く作業や、別のPCで続ける作業は、作業用のブランチにコミットしておく方が、git logで見つけやすくなります。
addの取り消しは関連記事「git addを取り消す:編集内容を残してステージから外す手順」、コミットの取り消しは「直前のコミットを取り消す:git reset --softで変更をステージに残す手順」、消したコミットの復旧は「git reset --hardで消したコミットを戻す:git reflogで元の位置を探す手順」を参照してください。
2026年10月18日、WSLのLinux・Git 2.53.0・非rootユーザーで掲載例を実行しました。退避前後と戻した後のgit status --short、git stash listとgit stash showの表示、--indexを付けない場合のステージの状態、popの衝突時の終了コード・表示とstashが残ること、--grep=WIPでは-mのstashが見つからないこと、IDで戻した内容、worktree間でstashの一覧が共有されることを照合しています。Git公式の説明は2026年10月18日時点の版(git-stashは2.56.0で更新)を参照しました。git gcによる削除は、日付を進めて検証していません。