GitStash
# 07.Git stash
stash就是隐藏的意思
# 在git stash出现之前
当我们在开发一个新功能的时候,突然来了一个紧急的bug要修复,此时我们可以创建一个分支去修复它;
但如果,切换会导致冲突的话,就会切换失败。我们来模拟下(先确保工作区是干净的)
$ git branch bug02
$ echo "test" >> 3-branch/branch.txt
$ cat 3-branch/branch.txt
Creating a new branch is quick and simple
test no fast forward
test
$ git add .
$ git commit -m "add test to branch.txt"
2
3
4
5
6
7
8
9
10
11
12
13
接下来,我们切换并修改branch.txt的最后一行,使得其和master分支不一样:
$ git switch bug02
Switched to branch 'bug02'
$ vim 3-branch/branch.txt
$ cat 3-branch/branch.txt
Creating a new branch is quick and simple
test no fast forward
fuk
2
3
4
5
6
7
8
9
接下来我们切换,果然,报错了:
$ git switch master
error: Your local changes to the following files would be overwritten by checkout:
3-branch/branch.txt
Please commit your changes or stash them before you switch branches.
Aborting
2
3
4
5
Git告诉我们可以提交后再切换;但是我们目前仅仅开发到一半,不想提交,怎么办?
# Git stash演示
Git提供了stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
$ git stash
Saved working directory and index state WIP on bug02: a2f5dc9 rm temp.txt
2
请读者务必也动手实践!
现在,用git status
查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地切换分支。
$ git status
On branch bug02
nothing to commit, working tree clean
$ cat 3-branch/branch.txt
Creating a new branch is quick and simple
test no fast forward
2
3
4
5
6
7
等后续修复完bug后,如何恢复现场呢?首先,我们的工作现场是存储在一个栈里的,我们可以查看当前有哪些工作现场:
$ git stash list
stash@{0}: WIP on bug02: a2f5dc9 rm temp.txt
2
有两种恢复方式:
- 用
git stash apply
恢复,但是恢复后,stash内容并不删除,你需要用git stash drop
来删除;类似读取栈的内容,但不弹出 - 用
git stash pop
,恢复的同时把stash内容也删了。
我们使用第二种方式,可以看到Git会将当前仓库状态显示出来:
$ git stash pop
On branch bug02
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: 3-branch/branch.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (a81ac38b932b00c0f934f613f823c33c7e37b10d)
2
3
4
5
6
7
8
9
并且文件内容也恢复了:
$ cat 3-branch/branch.txt
Creating a new branch is quick and simple
test no fast forward
fuk
2
3
4
你可以多次stash,恢复的时候,先用git stash list
查看,然后恢复指定的stash,用命令:
$ git stash apply stash@{0}
再用git stash list
查看,就看不到任何stash内容了:
$ git stash list
# 更多stash用法
我们在存储现场的时候,还可以加一些注释,方便我们回忆:git stash save "test"
$ git stash save "temp"
Saved working directory and index state On bug02: temp
peterjxl@peter MINGW64 /d/Projects/LearnGit (bug02)
$ git stash list
stash@{0}: On bug02: temp
2
3
4
5
6
更多stash的用法,就不一一演示了:
git stash clear
:清除堆栈中的所有内容
git stash show
:查看堆栈中最新保存的stash和当前目录的差异。
git stash show stash@{1}
:查看指定的stash和当前目录差异。
git stash branch
:从最新的stash创建分支。
# 复制一个提交
现在我们假设这样一个场景
- 我们从master分支上,创建了feature分支开发一个新功能
- 此时突然来了个比较紧急的bug,是master分支上的
- 我们从master分支上创建一个分支bug,并修复了该bug
- 继续回到feature分支开发
目前有这样一个问题,我们的feature分支也是从master分支上拉出来的,所以那个bug在当前分支也是存在的!那要怎么修复?一个方法是将bug再一次在feature分支上修复一次,但这样又花了不少时间做重复的事情。
git专门提供了一个cherry-pick
命令,让我们能复制一个特定的提交到当前分支。我们来演示下:
先删除其他分支,并确保当前工作区是干净的
$ git branch
* master
2
创建feature分支和bug分支:
$ git branch feature
$ git branch bug
$ git branch
bug
feature
* master
2
3
4
5
6
7
8
切换到bug分支上,并修改branch.txt,添加一个词组cherry-pick
$ git switch bug
$ vim 3-branch/branch.txt
$ cat 3-branch/branch.txt
Creating a new branch is quick and simple
test no fast forward
test cherry-pick
$ git add 3-branch/branch.txt
$ git commit -m "fix bug"
[bug 1794212] fix bug
1 file changed, 1 insertion(+), 1 deletion(-)
2
3
4
5
6
7
8
9
10
11
12
13
14
这里记录下commit id是1794212,后续会用到。
然后切换到master分支,合并bug分支
$ git switch master
$ git merge --no-ff -m "merged bug fix" bug
Merge made by the 'recursive' strategy.
3-branch/branch.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
2
3
4
5
然后切换到feature分支,并复制提交:
$ git cherry-pick 1794212
[feature 88085eb] fix bug
Date: Sat Jan 14 20:06:01 2023 +0800
1 file changed, 1 insertion(+), 1 deletion(-)
$ cat 3-branch/branch.txt
Creating a new branch is quick and simple
test no fast forward
test cherry-pick
2
3
4
5
6
7
8
9
Git自动给feature分支做了一次提交,注意这次提交的commit是88085eb
,它并不同于master的1794212
,因为这两个commit只是改动相同,但确实是两个不同的commit:
$ git log --oneline
88085eb (HEAD -> feature) fix bug
982423c add test to branch.txt
a2f5dc9 rm temp.txt
b194598 add temp.txt
2
3
4
5
用git cherry-pick
,我们就不需要在feature分支上手动再把修bug的过程重复一遍。