C:\git-stash-demo>git stash -u
Saved working directory and index state WIP on master: 95eff6b a.txt: set 1 as c
ontent
HEAD is now at 95eff6b a.txt: set 1 as content
C:\git-stash-demo>git status
# On branch master
nothing to commit, working directory clean
C:\git-stash-demo>git cat-file -p 95ef
tree eba2ef4205738a5015fc47d9cfe634d7d5eae466
parent 346fadefdd6ed2c562201b5ca37d1e4d26b26d54
author Will <doggy.huang@gmail.com> 1381450635 +0800
committer Will <doggy.huang@gmail.com> 1381450635 +0800
a.txt: set 1 as content
C:\git-stash-demo>git cat-file -p b79c
tree eba2ef4205738a5015fc47d9cfe634d7d5eae466
parent 95eff6b19a9494667985ed5da37427bb08b8cdd7
author Will <doggy.huang@gmail.com> 1381453061 +0800
committer Will <doggy.huang@gmail.com> 1381453061 +0800
index on master: 95eff6b a.txt: set 1 as content
C:\git-stash-demo>git cat-file -p 9b4e
tree b583bfe854b66756dd0f8ee96cab0c898193b5fd
author Will <doggy.huang@gmail.com> 1381453062 +0800
committer Will <doggy.huang@gmail.com> 1381453062 +0800
untracked files on master: 95eff6b a.txt: set 1 as content
從上述執行結果你應該可以從「訊息紀錄」的地方清楚看出這三個版本分別代表那些內容:
原本工作目錄的 HEAD 版本
原本工作目錄裡所有追蹤中的內容 (在索引中的內容)
原本工作目錄裡所有未追蹤的內容 (不在索引中的內容)
也就是說,他把「原本工作目錄的 HEAD 版本」先建立兩個暫時的分支,這兩個分支分別就是「原本工作目錄裡所有追蹤中的內容」與「原本工作目錄裡所有未追蹤的內容」之用,並在個別分支建立了一個版本以產生 commit 物件並且給予預設的 log 內容。最後把這三個分支,合併到一個「參照名稱」為 stash 的版本 (這也是個 commit 物件)。不僅如此,他還把整個「工作目錄」強迫重置為 HEAD 版本,把這些變更與新增的檔案都給還原,多的檔案也會被移除。
取回暫存版本
由於「工作目錄」已經被重置,所以變更都儲存到 stash 這裡,哪天如果你想要把這個暫存檔案取回,就可以透過 git stash pop 重新「合併」回來。如下所示:
C:\git-stash-demo>git status
# On branch master
nothing to commit, working directory clean
C:\git-stash-demo>git stash pop
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: a.txt
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# b.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (0e5b72c96fcf693e0402c40cd58f980bb3ff7efd)
你老闆或客戶「插單」的問題十分嚴重,經常改到一半就被迫插單。(這就是身為 IT 人的 BI 啊~~~XD) (BI = Business Intelligence 或另一層意思... Well, you know....)
我們延續上一個例子,目前工作目錄的狀態應該是有兩個檔案有變化,我們用 git status -s 取得工作目錄的狀態(其中 -s 代表顯示精簡版的狀態):
C:\git-stash-demo>git status -s
M a.txt
?? b.txt
現在,我們先建立第一個 stash 暫存版:
C:\git-stash-demo>git stash save -u
Saved working directory and index state WIP on master: 95eff6b a.txt: set 1 as content
HEAD is now at 95eff6b a.txt: set 1 as content
然後透過 git stash list 列出目前所有的 stash 清單,目前僅一份暫存版:
C:\git-stash-demo>git stash list
stash@{0}: WIP on master: 95eff6b a.txt: set 1 as content
C:\git-stash-demo>git status -s
C:\git-stash-demo>echo 1 > new.txt
C:\git-stash-demo>git status -s
?? new.txt
C:\git-stash-demo>git stash save -u
Saved working directory and index state WIP on master: 95eff6b a.txt: set 1 as c
ontent
HEAD is now at 95eff6b a.txt: set 1 as content
我們在再一次 git stash list 就可以看到目前有兩個版本:
C:\git-stash-demo>git stash list
stash@{0}: WIP on master: 95eff6b a.txt: set 1 as content
stash@{1}: WIP on master: 95eff6b a.txt: set 1 as content
你應該會很納悶,都沒有自訂的註解,過了幾天不就忘記這兩個暫存檔各自的修改項目嗎?沒錯,所以你可以自訂「暫存版」的紀錄訊息。我們透過 git stash save -u <message> 指令,就可自訂暫存版的註解:
C:\git-stash-demo>git stash -h
usage: git core\git-stash list [<options>]
or: git core\git-stash show [<stash>]
or: git core\git-stash drop [-q|--quiet] [<stash>]
or: git core\git-stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]
or: git core\git-stash branch <branchname> [<stash>]
or: git core\git-stash [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
[-u|--include-untracked] [-a|--all] [<message>]]
or: git core\git-stash clear
C:\git-stash-demo>git stash pop
Already up-to-date!
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# new.txt
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (5800f37937aea5fb6a1aba0d5a1598a940e70c96)
C:\git-stash-demo>git stash save -u "新增 new.txt 檔案"
Saved working directory and index state On master: 新增 new.txt 檔案
HEAD is now at 95eff6b a.txt: set 1 as content
C:\git-stash-demo>git stash list
stash@{0}: On master: 新增 new.txt 檔案
stash@{1}: WIP on master: 95eff6b a.txt: set 1 as content
C:\git-stash-demo>git stash list
stash@{0}: On master: 新增 new.txt 檔案
stash@{1}: WIP on master: 95eff6b a.txt: set 1 as content
C:\git-stash-demo>git stash apply "stash@{1}"
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: a.txt
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# b.txt
no changes added to commit (use "git add" and/or "git commit -a")
C:\git-stash-demo>git stash list
stash@{0}: On master: 新增 new.txt 檔案
stash@{1}: WIP on master: 95eff6b a.txt: set 1 as content
如果確定合併正確,你想刪除 stash@{1} 的話,可以透過 git stash drop "stash@{1}" 將特定暫存版刪除。
C:\git-stash-demo>git stash drop "stash@{1}"
Dropped stash@{1} (118cb8a7c0b763c1343599027d79f7b20df57ebf)
C:\git-stash-demo>git stash list
stash@{0}: On master: 新增 new.txt 檔案
如果想清理掉所有的暫存版,直接下達 git stash clear 即可全部刪除。
C:\git-stash-demo>git stash list
stash@{0}: On master: 新增 new.txt 檔案
C:\git-stash-demo>git stash clear
C:\git-stash-demo>git stash list
今日小結
Git 的 stash (暫存版) 機制非常非常的實用,尤其是在 IT 業界插單嚴重的工作環境下 (不只台灣這樣,世界各地的 IT 業界應該也差不多),這功能完全為我們量身打造,非常的貼心。在 Subversion 裡就沒有像 Git 這麼簡單,一個指令就可以把工作目錄與索引的狀態全部存起來。