git stash 的使用情境為何?讓我們先看一個例子:

當修改了 working directory 後,目前的 working directory 會成為 dirty 的。
而有時候會需要在 dirty 的情況下查看之前的 commit 或 pull,此時有以下 2 種作法:

  1. 將 working directory 的改動 commit 起來暫存
  2. 使用 git stash

假設目前情境如下:

When you are in the middle of something, your boss comes in and demands that you fix something immediately.
Traditionally, you would make a commit to a temporary branch to store your changes away, and return to your original branch to make the emergency fix.
- from git stash --help

Commit 的做法

1
2
3
4
5
6
7
8
9
10
11
hack hack hack
git switch -c "my_wip" // create new branch and switch
git commit -a -m "WIP"
git switch master
...
edit something
...
git commit -a -m "Fix in a hurry"
git switch my_wip
git reset --soft HEAD^
... continue hacking ...

Using git stash

1
2
3
4
5
6
7
8
hack hack hack
git stash // actually git stash push
...
edit something
...
git commit -a -m "Fix in a hurry"
git stash pop // explain later
... continue hacking ...

從上面的例子可以看到 git stash 相比使用 commit 再 reset 要來得簡潔許多。

由此可知,git stash 的用途就是將 local 的修改 stash(存放) 起來,之後可以拿出來使用,就像倉鼠一樣!

git stash 的 command

git stash 有哪些 command 呢?我們可以透過 git stash --help 查看。

以下將介紹一些常用的 command。

git stash push

git stash command 實際上就是 git stash push,想不到吧!git stash 就像是縮寫一樣。

而為什麼是叫做 push 呢?

當我們把東西 stash 起來的時候,是存放到一個 list 的結構內,我們可以透過 git stash list 查看。

1
2
3
$ git stash list
stash@{0}: WIP on dog: 053fb21 add dog 2
stash@{1}: WIP on cat: b174a5a add cat 2

所以如果要將東西放上這個 list,使用的是 push。

git stash 只會將已經 tracked 的 files stash 起來,那些新 create 的 files 並不會被 stash。
如果要將 Untracked files stash 起來,需要多加一個 flag:git stash push -u,當然,只打 git stash -u 也可以。

git stash list

同上所述,這個 command 會將目前的 stash list print 出來。

形式如下:

1
2
3
$ git stash list
stash@{0}: WIP on dog: 053fb21 add dog 2
stash@{1}: WIP on cat: b174a5a add cat 2

stash@{0} 是 stash 的代稱。

git stash pop

當我們將東西 stash 起來後,就像倉鼠一樣,將東西存放在頰囊內,是之後要拿出來吃的!

這時候就可以用到 git stash pop 這個指令,會將 list 最上面的 stash pop 出來,放到目前的 branch 上。

如果要指定某個要 pop 的 stash,可以在 git stash pop 後面加上 stash 的代稱,如下:

1
git stash pop stash@{0}

指定 stash 做操作的 operation 同樣適用在其他類似的 command。

git stash apply

操作同 git stash pop,不過並不會將 stash 從 stash list 移除。

git stash drop

將 stash 從 list 上直接移除,如果沒有指定哪個 stash 的話,會移除最新的 stash,也就是 stash@{0}。

進階操作

stash index

如果在原本的 working directory 中,其中有些修改已經 staged 起來,這時候如果要使用 stash,可以透過 git stash push --keep-index

在 pop 出來的時候特別指定連 index 也要 restore 即可,如下:

1
2
git stash push --keep-index
git pop --index

指定哪些要 stash

透過 push 的 --patch (or -p) flag,可以在後面指定要 stash 的 file 的路徑,如下:

1
git stash push --patch /path/to/file

path 也可以用 regular expression 表示。
像是 git stash push --patch **/to/**

此時 git 會開啟 interactive 的模式,一一確認這個 hunk(這名詞後文有解釋) 是否要 stash,如下:

1
2
3
4
5
6
7
8
9
diff --git a/test b/test
index acbd8ae..662d47a 100644
--- a/test
+++ b/test
@@ -10,6 +10,7 @@ test
(...)
+ test
(...)
Stash this hunk [y,n,q,a,d,/,e,?]?

[y,n,q,a,d,/,e,?] 解釋如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

hunk 是一個 files 中相對應的修改,可以透過 git diff 查看,一般顯示如下:

1
2
3
4
5
6
7
8
9
10
11
12
diff --git a/example.txt b/example.txt
index e69de29..d95f3ad 100644
--- a/example.txt
+++ b/example.txt
@@ -1,5 +1,5 @@
line 1
-line 2
+line 2 modified
line 3
-line 4
+line 4 modified
line 5

而如果在 git stash push --patch 後面沒有指定路徑的話,git 將會針對所有的 hunk 詢問是否要 stash。

如果想要省時間, -- 可以直接替代 --patch,用法如下:

1
git stash push -- /path/to/file

或者這樣也可以

1
git stash -- /path/to/file

如果使用 -- 指定路徑,git 將會直接 stash 起來,而不會跳出 interactive 的詢問。