git stash
情景:工作的时候,你正在项目中属于你的分支下开发一部分功能,但是还没有完善。Leader 突然叫你放下当前的工作,先修改项目中一个非常紧急的 BUG。修 BUG 嘛!家常便饭了。立即切回到上次发布版本(master 最近一次合并),新建一个分支去修复这个 BUG 。然而,在 checkout 到 master 的时候失败,提示你必须先 commit 当前分支的修改才能够 checkout 到其它分支。问题来了:当前分支的功能只是开发了一部分,不想那么快 commit。不 commit 的话,如果 reset 到前一次 commit 又浪费了之前所做的工作。怎么办?
Git 提供了一个存储机制,用户可以通过git stash或git stash save命令,将修改的跟踪文件与暂存改动存储到一个栈中。
1 | git stash - Stash the changes in a dirty working directory away |
注意,直接git stash或git stash save是不会将未跟踪文件暂存的。所以,当有未跟踪的文件的时候,要先add,或加 -u 参数
如,当前仓库中有文件test1.py和test2.py两个文件而且工作区都是清洁的,然后对test2.py进行修改,并且添加新文件test3.py。1
2
3
4
5
6
7
8
9
10
11
12
13
14$ git status
On branch lizs
nothing to commit, working tree clean
# change test2.py and add test3.py
$ echo " " >> test2.py
$ touch test3.py
$ git status -s
M test2.py
?? test3.py
# stashing the work
$ git stash
Saved working directory and index state WIP on lizs: 0df0b87 V1.0
$ git status -s
?? test3.py # Untracked files won't be stashed
那么,问题又来了。当我们 stash 修改的时候,发现还有文件没有被 stashed,想要将 stash 起来的修改恢复过来,重新 stash。要怎么做呢?
git stash list
查看 stashed 的记录1
2$ git stash list
stash@{0}: WIP on lizs: 0df0b87 V1.0git stash apply [<stash>]
将存储栈的一条记录重新应用到当前分支,如果不指定<stash>,会默认恢复最近一次 stash 记录存储内容。git stash apply在这里即相当于git stash apply stash@{0}。1
2
3
4$ git stash apply
$ git status -s
M test2.py
?? test3.py打开
test2.py文件可以看到其内容又回到了 stash 之前的状态了。我们再用git stash list查看存储栈的时候,发现刚刚的 stash 记录还在。存储的内容都恢复了,我觉得这条记录没意义了,想要删除了相应的 stash 记录,又要怎么做?git stash drop [<stash>]
删除存储栈的一条 stash 记录。如果不指定<stash>将会默认删除存储栈中最近一次的 stash 记录,git stash drop在这里即相当于git stash drop stash@{0}。1
2
3$ git stash drop
Dropped refs/stash@{0} (...)
$ git stash list # 可以看到最近一次的 stash 记录已经被删除掉了git stash pop [<stash>]
恢复并删除一条 stash 记录的内容。相当于git stash apply和git stash drop命令的结合。用法和git stash apply [<stash>]一样。
总结以上情境中操作:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22# change test2.py and add test3.py in the clean working tree
$ echo "# hello world" >> test2.py
$ touch test3.py
$ git add .
$ git status -s
M test2.py
?? test3.py
$ git stash
Saved working directory and index state WIP on lizs: 0df0b87 V1.0
$ git stash list
stash@{0}: WIP on lizs: 0df0b87 V1.0
$ git status
On branch lizs
nothing to commit, working tree clean.
# checkout to master fix bug
$ git checkout master
# create a new branch to fix bug
$ git checkout -b issue-01
# go back wo branch lizs to continue you work after finishing the bug
$ git checkout lizs
# restore your coding
$ git stash pop
注意,恢复存储栈中的内容的时候可能会有冲突需要合并。
git stash --include-untracked或git stash -u
将修改的跟踪文件与暂存改动,还有未跟踪的文件存储起来,即相当于先git add再git stash。1
2
3
4
5
6
7
8
9
10
11
12# change test2.py and add new file test3.py on a clean working tree
$ echo " " >> test2.py
$ touch test3.py
$ git status -s
M test2.py
?? test5.py
# stashing the change and untracked file
$ git stash -u
Saved working directory and index state WIP on lizs: 0df0b87 V1.0
$ git status
On branch lizs
nothing to commit, working tree clean.git stash save --keep-index
和git stash -u相反,通过git add命令跟踪的文件不存储。注意,--keep-index是git stash save的选项。即,git stash --keep-index是无效的。1
2
3
4
5
6
7
8
9
10
11# change test2.py and add new file test3.py on a clean working tree
$ echo " " >> test2.py
$ touch test3.py
$ git status -s
M test2.py
?? test3.py
$ git add -A
$ git stash save --keep-index
Saved working directory and index state WIP on lizs: 0df0b87 V1.0
$ git status -s
A test3.pygit stash --patch
Git 不会直接存储修改过的内容,但是会交互式地提示哪些修改要存储。git stash branch <branchname> [<stash>]
将 stash 的一个记录内容恢复在一个新创建的分支<branchname>上。<branchname>,新分支的名称;<stash>,可选,不指定默认为最近一次 stash。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28# change test2.py and add new file test3.py on a clean working tree
$ echo " " >> test2.py
$ touch test3.py
$ git status -s
M test2.py
?? test3.py
$ git stash list
stash@{0}: WIP on lizs: 0df0b87 V1.0
$ git status
On branch lizs
nothing to commit, working tree clean.
# restore the a stash on a new branch
$ git stash branch issue-01
Switched to a new branch 'issue-01'
On branch issue-01
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: test2.py
Untracked files:
(use "git add <file>..." to include in what will be committed)
test3.py
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (...)可以看到
git stash branch issue-01用分支 lizs 的一个 stash 记录的内容新建了一个 issue-01 分支,并且会自动删除该 stash 记录,当前位于 issue-01 分支下。那么 lizs 分支会怎么样呢?1
2
3
4
5$ git checkout lizs
$ git status -s
M test2.py
?? test3.py
$ git stash --list # the stash has been dropped回到 lizs 分支之后,发现用来创建新分支的 stash 的内容居然也恢复在了 lizs 分支!WTF!那这个命令有什么卵用?