Git スタッシュ(stash) 一時的に変更を退避

Git のスタッシュ(stash)の使い方についての覚書です。

git stash コマンドは、一時的に変更を退避させるための便利なツールです。これを使うことで、作業中の変更を一時的に保存し、別の作業を行ったり、他のブランチに切り替えたりすることができます。

関連ページ

作成日:2022年8月28日

スタッシュ 一時的に変更を退避(git stash)

英語の stash には「隠す」や「隠し場所」という意味があります。

スタッシュ(stash)はファイルの変更内容を一時的に記録しておくための領域(スタックのようなもの)と考えることができ、必要に応じて複数の変更内容を保存して取り出すことができます。

git stash コマンドを使うと、コミットを作らずに変更を一時的に保存しておき、後で取り出して作業中のブランチに復元することができます。

以下は Git Reference の git stash コマンドからの抜粋です。

git stash コマンドは、作業ディレクトリとインデックスの現在の状態を記録しておきたいが、クリーンな作業ディレクトリに戻りたい場合に使用します。このコマンドはローカルの変更を一時的に退避させ、作業ディレクトリを HEAD コミットと一致する状態に戻します。

例えば、以下のような場合に利用することができます。

  • 作業中の変更を一時的に退避する
    作業中に急に別のタスクに切り替える必要が生じたときや、コードのテストやデバッグを行うために、未コミットの変更を一時的に退避させて、後で戻ってくることができます。
  • 別のブランチへの切り替え
    現在のブランチでの変更を一時的に保存して、別のブランチに切り替えて作業することができます。
  • 変更を他のブランチに持っていく
    作業中のブランチで行った変更を別のブランチに持って行く必要がある場合、変更を一時的に保存し、その変更を別のブランチに持っていく(適用する)ことができます。

git stash -h で git stash コマンドのヘルプを表示できます。

% git stash -h  // ヘルプを表示
usage: git stash list [<log-options>]
   or: git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]
   or: git stash drop [-q | --quiet] [<stash>]
   or: git stash pop [--index] [-q | --quiet] [<stash>]
   or: git stash apply [--index] [-q | --quiet] [<stash>]
   or: git stash branch <branchname> [<stash>]
   or: git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
                 [-u | --include-untracked] [-a | --all] [(-m | --message) <message>]
                 [--pathspec-from-file=<file> [--pathspec-file-nul]]
                 [--] [<pathspec>...]]
   or: git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
                 [-u | --include-untracked] [-a | --all] [<message>]
   or: git stash clear
   or: git stash create [<message>]
   or: git stash store [(-m | --message) <message>] [-q | --quiet] <commit>

変更を退避(push)

作業中のファイル(変更)を保存するには、まだコミットしていない変更がある状態で git stash または git stash push を実行します。

変更を退避
git stash
git stash push

git stash push は新しいコマンドで、単に git stash で実行するよりも多くのオプションを指定することができます(より柔軟な機能を提供します)。

git stash に引数を何も指定しないで呼び出した場合 git stash push を呼び出すのと同じことになります。

基本的にはオプションなどを指定しない場合は git stash を使い、オプションを指定する場合は git stash push を使った方が良さそうです。

※ また、v 2.16.0以降では git stash save コマンドは非推奨とされており、代わりに git stash push コマンドを使用することが推奨されています(git stash save コマンドを使用することはできます)。

オプション(一部抜粋)
オプション 短縮形 意味
--all -a ステージ済みと未追跡の変更をすべて含めます
--message -m スタッシュに説明メッセージを添えることができます
--include-untracked -u 未追跡ファイルもスタッシュに含めます
--keep-index -k ステージ済みの変更は退避しない(スタッシュに含めない)
--staged -S ステージ済みの変更のみをスタッシュします

名前を付けて退避する -m

保存した内容を確認する際にどの変更かがわかりやすいように -m オプションを指定してスタッシュにメッセージ(名前)を付けて保存することができます。

git stash push -m "メッセージ"
git stash -m "メッセージ"

未追跡ファイルも退避する -u

デフォルトでは、追跡されていない状態(Untracked files)のファイルは退避されません。

新規作成したファイルなどの未追跡ファイルのファイルも含めて退避するには -u オプションを指定します。

git stash push -u
git stash -u

例えば、以下のようなコミットしていない変更がある場合、

% git status // ステータスを確認
On branch topic
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   sample1.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:   sample2.txt  // ステージされていない

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        sample3.txt // 追跡されていない

-u オプションを指定せずに git stash を実行すると、未追跡のファイルは退避されません。

% git stash  // または git stash push
Saved working directory and index state WIP on topic: 3d474b3 update content

% git status // ステータスを確認
On branch topic
Untracked files:  // 未追跡のファイルは残っている
  (use "git add <file>..." to include in what will be committed)
        sample3.txt

nothing added to commit but untracked files present (use "git add" to track)

この状態で他のブランチに切り替えると、未追跡のファイルは移動先のブランチに移動します。それが期待した動作でない場合は、問題になる可能性があります。

-u オプションを指定して実行すると、未追跡のファイルも退避されます。

% git stash push -u  // または git stash -u
Saved working directory and index state WIP on topic: 3d474b3 update content

% git status  // ステータスを確認
On branch topic
nothing to commit, working tree clean  // ワーキングツリーはクリーンになっている

退避した作業を表示(list)

変更を退避したら、git stash list コマンドで退避した作業の一覧を表示して確認します。

以下の例では、過去に保存した2つのスタッシュが表示されています(新しいものが上に表示されます)。

% git stash list  // 退避した作業の一覧を表示
stash@{0}: WIP on topic: 3d474b3 update content
stash@{1}: WIP on topic: 407a23d sample1 added

git stash list コマンドの出力は以下のようなフォーマットになっています。

stash@{n} : WIP on ブランチ名 : ハッシュ値 コミットメッセージ
  • stash@{n} :スタッシュ名(スタッシュの識別子)。n0 のスタッシュ stash@{0} が最新のもので一番上に表示されます。
  • WIP on ブランチ名 :WIP on の後にブランチ名が表示されます(WIP は Work In Progress の略)
  • ハッシュ値 コミットメッセージ:この部分はスタッシュを行ったときの HEAD の値

git stash push または git stash で変更を退避する際に -m オプションを使ってメッセージを指定すれば、「ハッシュ値 コミットメッセージ」の部分は指定したメッセージが表示されます。

% git stash push -m "my stash No.1"  // -m オプションを使ってメッセージを指定
Saved working directory and index state On topic: my stash No.1

% git stash list
stash@{0}: On topic: my stash No.1  // ブランチ名の後に指定したメッセージが表示される
stash@{1}: WIP on topic: 3d474b3 update content
stash@{2}: WIP on topic: 407a23d sample1 added
退避した各作業の要約を表示(show)

git stash show コマンドを使うとスタッシュ(退避した作業)の要約を表示できます。

スタッシュ名を省略して実行すると直近に退避した作業 stash@{0} の要約が表示されます。

% git stash show  // git stash show stash@{0} と同じ
file.txt | 2 ++
 1 file changed, 2 insertions(+)

 % git stash show stash@{1}
 sample.txt | 1 +
 1 file changed, 1 insertion(+)

差分を表示するには -p オプションを指定します。

% git stash show -p  //直近に退避した作業 stash@{0} の差分を表示
diff --git a/file.txt b/file.txt
index d95f3ad..9cf3e8f 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,3 @@
 content
+update
+additional update

% git stash show -p stash@{1}  // 1つ前(stash@{1})の退避した作業の差分を表示
diff --git a/sample.txt b/sample.txt
index e3aa9e2..883f904 100644
--- a/sample.txt
+++ b/sample.txt
@@ -1,2 +1,3 @@
 sample
 update
+additional text

退避した作業を戻して復元(apply)

退避した作業を戻して復元するには、復元したいブランチで git stash apply コマンドを実行します(または git stash pop コマンドを実行します)。

git stash apply スタッシュ識別子

以下を実行すると直近に退避した作業 stash@{0} を現在のブランチに適用して戻します。

% git stash apply stash@{0}

スタッシュの識別子を省略した場合は、直近のスタッシュを戻すので以下は上記と同じことです。

% git stash apply  // git stash apply stash@{0} と同じこと

保存した作業内容は変更を退避したときのブランチ以外のブランチにも適用することができます。

ステージングを維持したまま戻す --index

単にそのままスタッシュを戻すと、git add でステージングエリアに追加した変更もワーキングツリーに戻ってしまいます。

% git status // ステータスを確認
On branch topic
Changes to be committed: // git add でステージ済み
  (use "git restore --staged <file>..." to unstage)
        modified:   sample3.txt

% git stash   // 変更を退避
Saved working directory and index state WIP on topic: 48719dd content update and add new file

% git stash apply  // 変更を直近のスタッシュに戻す
On branch topic
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:   sample3.txt

no changes added to commit (use "git add" and/or "git commit -a")

--index オプションを付けて実行することで、ステージング状態(インデックス)を維持したまま戻すことができます。

% git status
On branch topic
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   sample3.txt

% git stash
Saved working directory and index state WIP on topic: 48719dd content update and add new file

% git stash apply --index  // ステージング状態を維持したまま戻す
On branch topic
Changes to be committed: // ステージ済みが維持される
  (use "git restore --staged <file>..." to unstage)
        modified:   sample3.txt

退避した作業を削除(drop)

退避した作業を元に戻しても、退避した作業内容はスタッシュの領域に残ったままになります。

git stash を実行するたびに退避した作業内容は保存されていきます。

必要がなくなったスタッシュ(退避した作業内容)は git stash drop コマンドで削除することができます。

git stash drop スタッシュ識別子

以下を実行すると直近に退避した作業 stash@{0} を削除します。

% git stash drop stash@{0}

apply 同様、スタッシュの識別子を省略した場合は、直近のスタッシュを削除するので以下は上記と同じことです。

% git stash drop
スタッシュを全て削除(clear)

退避した作業をすべて削除するには git stash clear コマンドを使います。

% git stash list // スタッシュの一覧を表示
stash@{0}: WIP on topic: 48719dd content update and add new file
stash@{1}: On topic: my stash No.1
stash@{2}: WIP on topic: 3d474b3 update content
stash@{3}: WIP on topic: 407a23d sample1 added

% git stash clear  // 退避した作業をすべて削除

% git stash list  // 全て削除されたので何も表示されない 

復元後に退避した作業を削除(pop)

git stash pop を使用すると、退避した作業を戻して復元した後、そのスタッシュ(退避した作業)を削除します。

つまり、git stash pop は git stash apply と git stash drop をまとめて実行してくれるコマンドです。

使い方は git stash apply とほぼ同じです。

以下を実行すると直近に退避した作業 stash@{0} を現在のブランチに適用して復元し、復元に使用したスタッシュ(退避した作業)を削除します。

% git stash pop stash@{0} 

スタッシュの識別子を省略した場合は、直近のスタッシュを戻すので以下は上記と同じことです。

% git stash pop 

以下は直近の退避した変更を git stash pop --index を実行してステージングを維持したまま復元し、同時にスタッシュを削除する例です。

// ステータスを表示
% git status
On branch topic
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   sample3.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:   sample2.txt

 // 未追跡ファイルもスタッシュに含め(-u)変更を退避
% git stash push -u
Saved working directory and index state WIP on topic: 48719dd content update and add new file

// スタッシュ一覧を表示(この例では上記のスタッシュのみ)
% git stash list
stash@{0}: WIP on topic: 48719dd content update and add new file

// 直近の退避した変更をステージングを維持したまま(--index)復元後、退避した変更を削除
% git stash pop --index
On branch topic
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   sample3.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:   sample2.txt

// git stash pop により、スタッシュが削除される
Dropped refs/stash@{0} (46c7164136843133e1c5a4b86311a161485f5eb5)

// スタッシュ一覧を表示(スタッシュは削除されているので何も表示されない)
% git stash list

スタッシュの使用例

以下は間違ったブランチでファイルを変更してしまいコミット前に気がついたので、スタッシュを使って変更を本来のブランチに適用する例です。

develop ブランチで作業するはずが、間違えて main ブランチで作業をしていて、ステータスを確認した際に(コミットする前に)間違いに気がついたとします。

% git status
On branch main  // main ブランチで作業をしていたことに気がつく
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   index.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        sample2.txt

この状態で git stash コマンドを実行すると最後のコミットからの変更を退避することができます。

この例の場合、未追跡(Untracked files)のファイルもあるので、 -u オプションを指定して git stash コマンドを実行します。

また、スタッシュのリストを確認する際に、わかりやすいように -m オプションを付けてメッセージを指定することにします。

% git stash push -um "WIP my stash 01"
Saved working directory and index state On main: WIP my stash 01

ステータスを確認すると現在いる main ブランチはクリーンな状態になっています。

% git status
On branch main
nothing to commit, working tree clean

git stash list コマンドで退避した作業のリストを表示してスタッシュを確認します。

% git stash list
stash@{0}: On main: WIP my stash 01

develop ブランチ(本来作業するはずだったブランチ)に切り替えます。

% git switch develop
Switched to branch 'develop'

git stash apply コマンドを実行して退避した作業を develop ブランチに適用して復元します。

--index はステージングを維持したまま戻すオプションです。--index を指定しない場合はステージングエリアに追加した変更もワーキングツリーに戻されます。

この例の場合、直近に退避した作業 stash@{0} を適用するので、stash@{0} は省略することができます。

% git stash apply --index stash@{0}  // この場合、stash@{0} は省略可能
On branch develop
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   index.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        sample2.txt

% git status  // ステータスを確認すると上記のレスポンスと同じ内容が表示される
On branch develop
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   index.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        sample2.txt

これで main ブランチでの変更作業を develop ブランチに持ってこれたので、develop ブランチで作業を進めることができます。

git stash apply コマンドの場合、退避した作業は削除されないので保存されたままになります。

% git stash list
stash@{0}: On main: WIP my stash 01

この例の場合は、退避した作業は不要なので、git stash drop コマンドで削除します。

この場合も、直近に退避した作業 stash@{0} を削除するので、stash@{0} は省略することができます。

% git stash drop stash@{0}  // この場合、stash@{0} は省略可能
Dropped stash@{0} (4f7239799e20089b5bee55643f50245761768c1c)

git stash apply コマンドの代わりに git stash pop コマンドを使用すれば、退避した作業の削除も同時に行ってくれるので、git stash drop を実行する手間を省けます。