「機能開発の途中だけど、急ぎで別のバグ修正を頼まれた」「まだコミットしたくないけど、他のブランチの様子をちょっと見たい」などなど、開発現場ではこんなふうに作業を中断せざるを得ない場面が頻繁に訪れます。そんな時、あなたはどうしていますか? 中途半端な状態で無理やりコミットしたり、変更内容をどこかに手動でコピーしたりしていませんか?
そんな悩みを一発で解決してくれる魔法のような機能が、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 clear
git 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 pop
git stash
は、日々の開発業務で発生する「作業の中断」にスマートに対応するための必須ツールです。
git stash
git stash pop
pop
とapply
の違いを理解して使い分けるpop --index
add
してから stash --staged
これらのポイントを押さえるだけで、あなたのGitライフはより快適で効率的なものになります。もう作業の中断を恐れる必要はありません。git stash
を使いこなし、ワンランク上の開発者を目指しましょう。