git stash を使用すると、作業コピーに加えた変更を一時的に棚上げし (または stash して)、他の作業をした後で戻って再適用できます。コード変更が完了しておらずまだコミットできない状態で、素早くコンテキストを切り替えて別の作業を行う場合には stash が便利です。

作業を隠す

git stash コマンドは、コミットされていない変更 (ステージングされたものおよびされていないもの) を取り出し、後で使用するために保存してから、作業コピーから取り消します。例:

$ git status
On branch main
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

$ git stash
Saved working directory and index state WIP on main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage

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

この時点で、自由に変更を加えたり、新しいコミットを作成したり、ブランチを切り替えたり、その他の Git 操作を実行することができます。準備が整ったら、stash しておいた変更に戻って、再適用します。

stash は作業しているローカルの Git リポジトリにのみ適用されます。プッシュ時にサーバーには転送されません。

隠していた変更を再適用する

以前に stash した変更は、git stash pop を使用して再適用できます。

$ git status
On branch main
nothing to commit, working tree clean
$ git stash pop
On branch main
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Dropped refs/stash@{0} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

stash をポップすると、stash から変更が削除され、作業コピーに再適用されます。

または、作業コピーに変更を再適用した上でgit stash apply を使用してその変更を stash に維持することも可能です。

$ git stash apply
On branch main
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

これは、stash した変更を複数のブランチに適用するのに便利です。

stash の基本を理解したところで、git stash について注意することが1つあります。既定では、Git は未追跡ファイルや無視されたファイルに対する変更を stash しません

未追跡または無視されたファイルを隠す

既定では、git stash を実行すると以下の変更が stash されます。

  • インデックスに追加された変更 (ステージングされた変更)
  • Git によって現在追跡されているファイルに対する変更 (ステージングされていない変更)

ただし、以下は stash されません

  • まだステージングされていない作業コピー内の新しいファイル
  • 無視された ファイル

したがって、上記の例に 3 番目のファイルを追加しても、それをステージングしないと (つまり、git add を実行しない場合)、git stash はそのファイルを stash しません。

$ script.js

$ git status
On branch main
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Untracked files:

    script.js

$ git stash
Saved working directory and index state WIP on main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage

$ git status
On branch main
Untracked files:

    script.js

-u オプション (または --include-untracked) を追加すると、追跡対象外のファイルも git stash で stash できます。

$ git status
On branch main
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Untracked files:

    script.js

$ git stash -u
Saved working directory and index state WIP on main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage

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

無視された ファイルへの変更を含めることもできます。それには、-a オプション (または --all) を git stash の実行時に渡します。

Git Stash のオプション

複数の stash の管理

使用できる stash は1つに限定されているわけではありません。git stash を数回実行して複数の stash を作成し、git stash list を使用して作成した stash を表示できます。既定では、stash は、stash の作成元のブランチやコミット上にある "WIP" (進行中の作業) として識別されます。しばらくすると、各 stash に含まれているものを覚えておくことが難しくなる場合があります。

$ git stash list
stash@{0}: WIP on main: 5002d47 our new homepage
stash@{1}: WIP on main: 5002d47 our new homepage
stash@{2}: WIP on main: 5002d47 our new homepage

もう少し事情がわかるように、git stash save "message" を使用して stash に説明文を付けることをお勧めします。

$ git stash save "add style to our site"
Saved working directory and index state On main: add style to our site
HEAD is now at 5002d47 our new homepage

$ git stash list
stash@{0}: On main: add style to our site
stash@{1}: WIP on main: 5002d47 our new homepage
stash@{2}: WIP on main: 5002d47 our new homepage

既定では、git stash pop は直近に作成された stash を再適用します。stash@{0}

最後の引数として識別子を渡すことで、再適用する stash を選択できます。たとえば、次のようになります。

$ git stash pop stash@{2}

stash diffs の表示

git stash show を使用すると、stash の要約を表示できます。

$ git stash show
 index.html | 1 +
 style.css | 3 +++
 2 files changed, 4 insertions(+)

stash のすべての差分を表示するには -p オプション (または --patch) を渡します。

$ git stash show -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+  text-decoration: blink;
+}
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>

部分的に隠す

また、単一のファイルや複数のファイル、ファイル内の個別の変更を選んで stash できます。git stash-p オプション (または --patch) を渡すと、作業コピーで変更された各「ハンク」で処理を反復して、その変更を stash するかを確認するメッセージが表示されます:

$ git stash -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+  text-decoration: blink;
+}
Stash this hunk [y,n,q,a,d,/,e,?]? y
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>
Stash this hunk [y,n,q,a,d,/,e,?]? n
Git Stash -p

? を入力すると、ハンクコマンドの全リストを取得できます。よく使用されるコマンドは次のとおりです。

コマンド 説明
/ 正規表現を使用してハンクを検索
サポート
n このハンクを隠さない
q 終了 (既に選択されているハンクはすべて stash されます)
s この変更差分ブロックを小さなブロックに分割
これからは この変更差分ブロックを stash

明示的な「中止」コマンドはありませんが、キーボードで CTRL-C (SIGINT) を押すと stash プロセスを中止します。

stash からのブランチの作成

ブランチでの変更が stash の変更と異なる場合、stash の変更を適用しようとすると競合が発生する可能性があります。代わりに、git stash branch を使用して新しいブランチを作成し、そこに棚上げ (stash) しておいた変更を適用することができます。

$ git stash branch add-stylesheet stash@{1}
Switched to a new branch 'add-stylesheet'
On branch add-stylesheet
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Dropped refs/stash@{1} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

これは、stash を作成したコミットをベースにした新しいブランチをチェックアウトし、stash しておいた変更をそのブランチに適用します。

stash のクリーンアップ

特定の stash が必要なくなった場合は、git stash drop で削除できます。

$ git stash drop stash@{1}
Dropped stash@{1} (17e2697fd8251df6163117cb3d58c1f62a5e7cdb)

または、次の方法ですべての stash を削除できます。

$ git stash clear

git stash の使用方法

git stash の使用方法のみが必要な場合は、この先を読まなくてもかまいません。ただし、Git (と git stash) の仕組みに関心がある場合は、このまま読み進めてください。

stash はコミットオブジェクトとしてご使用のリポジトリ内に実際にエンコードされます。.git/refs/stash にある特別な ref は最近作成された最新の stash をポイントし、以前に作成された stash は stash ref の reflog により参照されます。このため、stash@{n}: で stash を参照すると、実際には stash ref の nth reflog エントリーを参照していることになります。stash は単なるコミットにすぎないため、git log で調べることができます。

$ git log --oneline --graph stash@{0}
*-.   953ddde WIP on main: 5002d47 our new homepage
|\ \ 
| | * 24b35a1 untracked files on main: 5002d47 our new homepage
| * 7023dd4 index on main: 5002d47 our new homepage
|/ 
* 5002d47 our new homepage

単一の git stash 操作では、stash の内容に応じて 2 つまたは 3 つのコミットが新たに作成されます。上の図のコミットに関する説明は以下のとおりです。

  • stash@{0} は、git stash の実行時に作業コピー内の追跡対象ファイルを保存するための新しいコミット
  • stash@ {0} の最初の親、git stash 実行時に HEAD にあった既存のコミット
  • stash@{0} の 2 番目の親は、git stash を実行した時のインデックスを表す新しいコミットです。
  • stash@{0} の 3 番目の親は、git stash の実行時に作業コピー内にあった未追跡ファイルを表す新しいコミットです。この 3 番目の親は次の条件下でのみ作成されます。
    • 作業コピー内に実際に未追跡ファイルが含まれていた。
    • --include-untracked または --all オプションを指定して git stash を呼び出した。

git stash でワークツリーとインデックスをコミットとしてエンコードする仕組み:

  • stash する前に、作業ツリーに追跡済みファイル、未追跡ファイル、および無視されたファイルに対する変更が含まれている場合があります。これらの変更の一部は、インデックスにステージングされている場合もあります。

    stash を実行する前に
  • git stash を呼び出すと、DAG の2つの新しいコミットとして、追跡済みファイルへの変更がエンコードされます。1つはステージングされていない変更で、もう1つはインデックスにステージングされた変更です。特別な refs/stash ref が更新され、これらのコミットをポイントします。

    git stash
  • --include-untracked オプションを使って追跡対象外ファイルへの変更を追加コミットとしてエンコードすることもできます。

    Git stash --include-untracked
  • --all オプションでは、無視されたファイルと追跡対象外のファイルへの変更を同じコミットに含められます。

    Git Stash --all

git stash pop を実行すると、上記のコミットの変更が作業コピーとインデックスの更新に使用されます。stash reflog がシャッフルされて、ポップされたコミットは削除されます。ポップされたコミットはすぐには削除されませんが、将来のガベージコレクションの候補になります。

Git を学習する準備はできていますか?

この対話式チュートリアルを利用しましょう。

今すぐ始める