「機能開発の途中だけど、急ぎで別のバグ修正を頼まれた」「まだコミットしたくないけど、他のブランチの様子をちょっと見たい」などなど、開発現場ではこんなふうに作業を中断せざるを得ない場面が頻繁に訪れます。そんな時、あなたはどうしていますか? 中途半端な状態で無理やりコミットしたり、変更内容をどこかに手動でコピーしたりしていませんか?
そんな悩みを一発で解決してくれる魔法のような機能が、Gitの git stash(スタッシュ) です。この記事を読めば、git stashの概念から応用までを完全にマスターし、あなたの開発効率を劇的に向上させることができます。
git stashとはgit stashとは、まだコミットしていない作業内容(変更)を、一時的に別の場所に退避させておく ための機能です。
たとえば、あなたは今、机の上でプラモデルを作っています。パーツを切り出し、接着剤でくっつけ始めたところです(=コーディング中)。そこへ急な来客があり、机をすぐに片付けなければならなくなりました(=緊急の修正依頼)。この時、作りかけのプラモデルを箱にしまって、机の上を一旦まっさらにしますよね。来客対応が終わったら、また箱から取り出して作業を再開できます。
この「一時的に箱にしまう」という行為が、まさにgit stashです。git stashを使うと、作業ディレクトリを最後にコミットしたきれいな状態に戻せるので、安心して別の作業に取り掛かることができます。
git stashの基本的な使い方git stashの操作は非常にシンプルです。基本的な流れは以下の3ステップです。
git stash / git stash push)現在のブランチで行った変更を一時退避させます。最も基本的なコマンドは git stash ですが、これは git stash push の省略形です。
どの作業を退避させたか後で分かるように、メッセージを付けておくことを推奨します。メッセージを付けるには push サブコマンドと -m ( --message ) オプションを使います。メッセージを付与しておかないと、後で見返したときに「これなんの履歴だっけ?」となること請け合いです。とくに、git stash popせずstashリストに残りっぱなしだとこうなりがち。
# メッセージを付けてstashに退避
$ git stash push -m "WIP: ログイン画面のUI調整中"
Saved working directory and index state On feature/new-login: WIP: ログイン画面のUI調整中もちろん、メッセージ無しで退避することも可能です。
# メッセージ無しでstashに退避
$ git stash
# or
$ git stash pushすぐgit stash popするなら、このような方法でも問題ないと思います。
save と push の違い以前は git stash save "メッセージ" というコマンドが使われていましたが、現在は非推奨(deprecated)とされています。機能は git stash push -m "メッセージ" と同じですが、今後は push を使うようにしましょう。
git stash list)退避させた作業は、git stashのリストに積み重なっていきます。listコマンドで確認できます。
$ git stash list
stash@{0}: On feature/new-login: WIP: ログイン画面のUI調整中
stash@{1}: On feature/old-feature: WIP on feature/old-feature: ...stash@{0}が一番新しく退避した作業です。古いものほど数字が大きくなります。
git stash apply / git stash pop)退避した作業を元に戻して、作業を再開します。復元には2つのコマンドがあります。
# 最新のstashを復元(stashはリストに残る)
$ git stash apply
# 最新のstashを復元(stashはリストから削除される)
$ git stash popデフォルトでは最新のstash@{0}が復元されます。どちらのコマンドを使うべきかについては、次のセクションで詳しく解説します。
pop vs apply:どちらを使うべき?git stashを復元する2つのコマンド、popとapplyには明確な違いがあります。
git stash pop: 復元 + stashリストから削除
git stash apply: 復元のみ。stashリストには残る
使い分けのポイント
| コマンド | 動作 | おすすめのシーン |
|---|---|---|
git stash pop |
復元して、リストから削除する | 基本はこれ。退避した作業を元に戻して作業を再開するとき |
git stash apply |
復元するが、リストには残したまま | 同じ変更を複数のブランチに適用したいとき |
特別な理由がなければ、まずはpopを使えばいいと覚えておけば、とりあえず問題ないと思います。
git stash応用テクニック基本操作を覚えたら、さらに便利な応用テクニックもマスターしましょう。
stash@{n}のように番号を指定することで、最新ではないstashを操作できます。
# 2番目(stash@{1})のstashの変更内容を確認
$ git stash show stash@{1}
# 3番目(stash@{2})のstashを復元(リストには残る)
$ git stash apply stash@{2}
# 2番目(stash@{1})のstashを削除
$ git stash drop stash@{1}-u)git addしていない新規作成ファイル(Untracked files)は、デフォルトではgit stashの対象になりません。これらも一緒に退避させたい場合は-uオプションを付けます。
# 未追跡ファイルも含めてstash
$ git stash -u
# or
$ git stash --include-untrackedケースバイケースではあるものの、個人的には比較的よく利用するオプションです。というのも、しっかりこまめにgit addしてないからです_( _´ω`)_ペショ
-a).gitignoreで意図的に無視しているファイルも含め、すべての変更を退避させたい場合は-aオプションを使います。
# 無視ファイル、未追跡ファイルも含めて全てstash
$ git stash -a
# or
$ git stash --allたとえば、「デバッグ中に急遽別のバグ対応をしなければならない」という場合が、このオプションを利用するケースでしょう。大抵、デバッグ用のコードなどは.gitignoreで意図的に無視している場合が多いため、「デバッグ途中の状態を保持しておきたい」となると、.gitignoreで意図的に無視しているファイルも退避する対象に含める必要があるからです。逆に言えば、そのようなケースでない場合は、あまり利用しないオプションだと思います。
-S / --staged )git addした変更(ステージングエリアにある変更)のみをgit stashしたい場合において、非常に便利なオプションです。
git addしたものの、コミットメッセージを考えたり、関連する変更をもう少し加えたりしたい。でも、ステージングしていない変更(デバッグ用のコードなど)はgit stashに含めたくない…そんな場面で役立ちます。
# 1. 変更Aと変更Bを行う
# (file.txt に A を追記, debug.log に B を追記)
# 2. コミットしたい変更Aだけをステージング
$ git add file.txt
# 3. ステージングした変更だけをstash
$ git stash --staged
Saved working directory and index state WIP on main: ...
# この時点で、file.txtの変更は退避され、
# debug.logの変更は作業ディレクトリに残ったままになるapplyとpopでステージング状態も復元する (--index)git stashする際にステージングされていた変更は、applyやpopで復元する際にもその状態を維持したいですよね。そんな時に使うのが--indexオプションです。
通常、git stash popを実行すると、退避した変更はすべて「ステージングされていない状態」で作業ディレクトリに戻ります。
しかし、--indexオプションを付けて復元すると、git stashした時点でのステージング状態が再現されます。
# 1. file_A.txt と file_B.txt を変更
# 2. file_A.txt のみステージング
$ git add file_A.txt
# 3. stashに退避
$ git stash
# ... (別の作業) ...
# 4. --index を付けて復元
$ git stash pop --index
# この時点で `git status` を確認すると...
# Changes to be committed:
# (use "git restore --staged <file>..." to unstage)
# modified: file_A.txt <- ステージング状態が復元されている。
#
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git restore <file>..." to discard changes in working directory)
# modified: file_B.txtこのオプションを使えば、「この変更はコミットする予定だった」という状態まで正確に復元できるため、作業の再開がよりスムーズになります。
git stash clear)溜まったstashをすべて一括で削除します。一度削除すると元に戻せないので注意して利用してください。というか、あまりこのコマンドは個人的には使ったことがありません。git stash popして残さないからかもしれません。
# 全てのstashを削除
$ git stash cleargit stash具体的なシナリオでgit stashの使い方を見てみましょう。
あなたはfeature/new-designブランチで新デザインの実装中です。しかし、上司から「公開中のサイトで緊急のバグが見つかったから、すぐに修正して。」と頼まれました。このとき、現在対応している修正をいったん横において、バグ対応する必要があります。このようなときにgit stashを利用します。
# 1. 現在の作業をstashに退避
$ git stash push -m "WIP: 新デザインのヘッダー実装中"
# 2. メインブランチに移動し、最新の状態にする
$ git switch main
$ git pull origin main
# 3. バグ修正用のブランチを作成して修正作業
$ git switch -c hotfix/critical-bug
# ... (バグを修正してコミット)
$ git commit -am "Fix: 致命的なバグを修正"
# 4. mainブランチにマージしてプッシュ
$ git switch main
$ git merge hotfix/critical-bug
$ git push origin main
# 5. 元の作業ブランチに戻る
$ git switch feature/new-design
# 6. 退避しておいた作業を復元して再開。
$ git stash popこれで、コミットを汚すことなく、スマートに緊急対応ができました。
上手く行かないデバッグの気分転換に、別のブランチの進捗状況を確認したいとします。その際は、中途半端になっている現在のブランチをどうにかしないといけません。そのようなときにgit stashを利用します。
# 1. 中途半端な作業を一時退避
$ git stash push -m "WIP: feature/A のロジック実装途中"
# 2. 確認したいブランチに移動
$ git switch feature/B
# ... (コードの確認や議論) ...
# 3. 元の作業ブランチに戻り、作業を再開
$ git switch feature/A
$ git stash popgit stashは、日々の開発業務で発生する「作業の中断」にスマートに対応するための必須ツールです。
git stashgit stash poppopとapplyの違いを理解して使い分けるpop --indexadd してから stash --stagedこれらのポイントを押さえるだけで、あなたのGitライフはより快適で効率的なものになります。もう作業の中断を恐れる必要はありません。git stashを使いこなし、ワンランク上の開発者を目指しましょう。