本篇文章,是基于我自用Linux系统中的自定义文件夹“test_rep”,当做示例演示
具体Git仓库的目录在:/usr/local/git/test_rep
软件开发中,bug 就像家常便饭一样。有了 bug 就需要修复,在 Git 中,某种意义上每个 bug 都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
假设当你接到一个修复一个代号101的 bug 的任务时,按照咱说的“某种意义”,想创建一个分支issue-101
来修复它,但是,等等,当前正在dev
上进行的工作还没有提交。
在模拟之前,我需要模拟的创建一个dev
分支,并执行了几个操作:
$ git switch -c dev
Switched to a new branch 'dev'
#查看git工作区中的文件
$ ll
-rw-r--r-- 1 root root 158 Dec 6 19:47 read.txt
-rw-r--r-- 1 root root 21 Nov 30 15:06 test.txt
由上得知,有两个文件read.txt
和test.txt
。此时追加一个文件:
$ touch Hello.java
#追加到暂存区
$ git add Hello.java
#查看一下仓库状态
$ git status
On branch dev
Changes to be committed:
(use "git restore --staged ..." to unstage)
new file: Hello.java
OK,并不是你不想提交,而是工作只进行到一半(摸鱼肯定是存在的,空文件而已),还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该 bug,怎么办?
Git还提供了一个stash
功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
$ git stash
Saved working directory and index state WIP on dev: e7dcca3 ... #后面省略
现在,用git status
查看工作区,就是干净的(除非有没有被 Git 管理的文件),因此可以放心地创建分支来修复bug。
$ git checkout master
On branch dev
nothing to commit, working tree clean
此时,就可以确定要在哪个分支上修复 bug,假定需要在master
分支上修复,就从master
创建临时分支:
#切换到master分支
$ git switch master
Switched to branch 'master'
#在master分支创建新分支并切换到新分支,假设文章前说的issue-101分支
$ git switch -c issue-101
Switched to a new branch 'issue-101'
现在修复 bug,假设 bug 在文件test.txt
中:
#issue-101分支
#随便增加点什么
$ vim test.txt
#wq保存
提交修改的test.txt
文件:
#issue-101分支
$ git add test.txt
$ git commit -m 'fix bug 101'
[issue-101 a1ecaeb] fix bug 101
1 file changed, 1 insertion(+)
修复完成后,切换到master
分支,并完成合并,最后删除issue-101
分支(删除不删除的看你心情吧):
$ git switch master
Switched to branch 'master'
$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
test.txt | 1 +
1 file changed, 1 insertion(+)
只要不摸鱼,bug 修复也就几分钟的事!现在,是时候接着回到dev
分支干活了:
$ git switch dev
Switched to branch 'dev'
#查看状态
$ git status
On branch dev
nothing to commit, working tree clean
工作区是干净的,别着急,刚才不是把工作现场“储藏”起来,用git stash list
命令看看:
#dev分支下
$ git stash list
stash@{0}: WIP on dev: e7dcca3 用no-ff 测试merge #此处会是您最会一次提交的注释,我这里是这样的
如上,stash@{0}
可以粗浅的理解为 stash 的一个存储id,毕竟有时候可能有多个工作现场需要“储藏”;后面的 commit 注释是我本机测试环境下的,您的肯定会和我不不一样,当然你要是学着我来操作的,那就可能一样了。
继续,工作现场还在,Git 把 stash 内容存在某个地方了,但是需要恢复一下,有两个办法:
第一个办法是用git stash apply
恢复,但是恢复后,stash 内容并不删除,你需要用git stash drop
来删除;
第二个办法是用git stash pop
,恢复的同时把 stash 内容也删了(这个是我想用的):
#dev分支下
$ git stash pop
On branch dev
Changes to be committed:
(use "git restore --staged ..." to unstage)
new file: Hello.java
Dropped refs/stash@{0} (2ff33b09d4ca086cd894dc73e96893119a7270f1)
再用git stash list
查看,就看不到任何 stash 内容了:
$ git stash list
当然,你可以多次 stash,恢复的时候,先用git stash list
查看,然后恢复指定的 stash,用命令:
$ git stash apply stash@{0} #通过刚才说的类似id的恢复
到此,可以利用git status
看看您一开始dev
分支下的状态:
#dev分支下
$ git status
肯定又回到你刚才最早摸鱼的时候那种状态下。
刚才的操作是在 master 分支上修复了 bug 后,我们要想一想,dev 分支是早期从 master 分支分出来的,所以,这个 bug 其实在当前 dev 分支上也存在。
那怎么在 dev 分支上修复同样的 bug ?重复操作一次,提交不就行了?有木有更简单的方法?
有!
同样的 bug,要在 dev 上修复,我们只需要把刚才 commit时的那个fix bug 101
这个提交所做的修改“复制”到 dev 分支。注意:我们只想复制fix bug 101
这个提交所做的修改,并不是把整个 master 分支 merge 过来。
回看上面的博文,在我本机测试环境下,commit “fix bug 101”时,Git 给我反馈的是[issue-101 a1ecaeb] fix bug 101
,其中我这里的a1ecaeb
,是这次提交给定的 ID(注意,你的环境肯定和我的不一样),我们可以利用这个 ID 来操作,Git 专门提供了一个cherry-pick
命令,让我们能复制一个特定的提交到当前分支:
#dev分支下
#首先需要将所有的操作commit
#我这里只是追加了一个新的文件Hello.java
$ git commit -m 'append Hello.java'
[dev 274f6a9] append Hello.java
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 Hello.java
#将dev分支下所有的修改提交之后才可以执行cherry-pick
$ git cherry-pick a1ecaeb #注意,这个id一定得是您测试环境下的id,这里id只是我这里测试的id,你我肯定不一样
[dev a845a9d] fix bug 101
Date: Tue Dec 6 20:32:32 2022 +0800
1 file changed, 1 insertion(+)
如上,将 dev 分支下所有的修改提交之后才可以执行cherry-pick
。还有,刚才提到的那个 ID,如果您忘记了,完全可以切到 master
分支下,通过git log
查看到提交的日志信息,其中包括 ID。最后,Git 自动给dev
分支做了一次提交,这个提交虽然是同步之前的 bug,但是它属于两个不同的提交,所以其 ID 肯定不同。
有些聪明的童鞋会想了,既然可以在 master 分支上修复 bug 后,在 dev 分支上可以“重放”这个修复过程,那么直接在 dev 分支上修复 bug,然后在 master 分支上“重放”行不行?当然可以,不过你仍然需要git stash
命令保存现场,才能从 dev 分支切换到 master 分支。