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 这么简单,一个指令就可以把工作目录与索引的状态全部存起来。