git stash

git stash temporarily shelves (or stashes) changes you've made to your working copy so you can work on something else, and then come back and re-apply them later on. Stashing is handy if you need to quickly switch context and work on something else, but you're mid-way through a code change and aren't quite ready to commit.

作業を隠す

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

$ git status
On branch master
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 master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch master
nothing to commit, working tree clean

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

Note that the stash is local to your Git repository; stashes are not transferred to the server when you push.

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

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

$ git status
On branch master
nothing to commit, working tree clean
$ git stash pop
On branch master
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 master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html

This is useful if you want to apply the same stashed changes to multiple branches.

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

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

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

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

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

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

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

$ script.js
$ git status
On branch master
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 master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch master
Untracked files:
script.js

Adding the -u option (or --include-untracked) tells git stash to also stash your untracked files:

$ git status
On branch master
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 master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch master
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 master: 5002d47 our new homepage
stash@{1}: WIP on master: 5002d47 our new homepage
stash@{2}: WIP on master: 5002d47 our new homepage

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

$ git stash save "add style to our site"
Saved working directory and index state On master: add style to our site
HEAD is now at 5002d47 our new homepage
$ git stash list
stash@{0}: On master: add style to our site
stash@{1}: WIP on master: 5002d47 our new homepage
stash@{2}: WIP on master: 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(+)

Or pass the -p option (or --patch) to view the full diff of a stash:

$ git stash show -p
diff --git a/style.cssb/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.htmlb/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>

部分的に隠す

You can also choose to stash just a single file, a collection of files, or individual changes from within files. If you pass the -p option (or --patch) to git stash, it will iterate through each changed "hunk" in your working copy and ask whether you wish to stash it:

$ git stash -p
diff --git a/style.cssb/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.htmlb/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

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

コマンド Description
/ 正規表現を使用してハンクを検索
サポート
n このハンクを隠さない
q quit (any hunks that have already been selected will be stashed)
s この変更差分ブロックを小さなブロックに分割
y この変更差分ブロックを stash

There is no explicit "abort" command, but hitting CTRL-C(SIGINT) will abort the stash process.

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 master: 5002d47 our new homepage
|\ \
| | * 24b35a1 untracked files on master: 5002d47 our new homepage
| * 7023dd4 index on master: 5002d47 our new homepage
|/
* 5002d47 our new homepage

Depending on what you stashed, a single git stash operation creates either two or three new commits. The commits in the diagram above are:

  • stash@{0}, a new commit to store the tracked files that were in your working copy when you ran git stash
  • stash@{0}'s first parent, the pre-existing commit that was at HEAD when you ran git stash
  • stash@{0} の 2 番目の親は、git stash を実行した時のインデックスを表す新しいコミットです。
  • stash@{0} の 3 番目の親は、git stash の実行時に作業コピー内にあった未追跡ファイルを表す新しいコミットです。この 3 番目の親は次の条件下でのみ作成されます。
    • 作業コピー内に実際に未追跡ファイルが含まれていた。
    • --include-untracked または --all オプションを指定して git stash を呼び出した。

How git stash encodes your worktree and index as commits:

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

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

    git stash
  • Using the --include-untracked option also encodes any changes to untracked files as an additional commit.

    Git stash --include-untracked
  • Using the --all option includes changes to any ignored files alongside changes to untracked files in the same commit.

    Git Stash --all

     

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

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

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

今すぐ始める