VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • Git应用详解第四讲:版本回退的三种方式与stash(2)

image-20200414180953703

git revert HEAD~n

该指令的作用为重做所在分支的倒数第n+1次提交,会发生冲突,需要手动合并,完成重做操作。过程与上述一致,这里就不再赘述了。

总结:常用git revert commit_id这种方式。

3.撤销revert操作

思路很简单,再次通过revert操作取消上一次的revert操作(即所谓"负负得正")。

操作前,dev分支上的提交记录和test.txt文件内容如下:

image-20200414153206034

通过:git revert --no-edit f4a95重做提交dev2--no-edit表示不修改新增提交的注释):

image-20200414153456451

重做后,多了一次提交,并且test.txt文件中删除了dev2这一行内容。此时,可以通过:

复制代码
git revert --no-edit 582d127

重做上一次重做操作,以此达到取消上一次重做操作的目的:

image-20200414153724455

如上图所示,虽然多出了一次提交,但是test.txt文件中被删除的dev2内容被恢复了,这样就撤销了revert操作。

Ⅲ.git checkout

1.git checkout commit_id

使用checkout可以进行版本回退,如直接使用:

复制代码
git checkout cb214 

回退到提交3rd,此时会出现如下提示:

image-20200311111540863

注意到,切换后HEAD指向的不再是master分支,而是cb214...即第三次提交,查看历史提交记录:

image-20200311111719389

可看到只有3次提交,什么意思呢?如下图所示:

image-20200412001646768

image-20200311112656834

通过git checkoutHEAD指针指向了第3次提交,可以将它想象为一个新的分支。但是却没有实际创建分支,即此时head指向的由提交1~3组成的commit对象链条处于游离状态;

接着,在HEAD还指向游离的提交节点3的基础上对文件做出新的修改:

image-20200311113237150

  • 此时如果我们切换回master分支,会出现下列错误

image-20200311113209483

提示显示:如果没有保存就从游离的提交上切换到master分支,这一修改就会被checkout命令覆盖。我们可以在切换前进行一次提交操作:

image-20200311113625297

此时的状态为:

image-20200412002213790

  • 在游离的Commit对象链中进行了一次提交之后,再次通过:git checkout master切换到master分支:

image-20200311114055018

提示大意为:如果没有任何分支指向刚才在游离的Commit对象链中进行的提交,那么该提交就会被忽略。此时的状态如下图所示:

image-20200412002655921

如果想要创建一个分支保存(指向)这条游离的Commit对象链,现在就是很好的时机。根据上述提示的命令:

复制代码
git branch mycommit  c4d5cc3

创建指向commit_idc4d5cc3的提交(即上述的提交节点5)的分支mycommit

image-20200311115117279

由此游离的commit对象链得以被新分支所指向,并得到了保存,此时的状态如下图所示:

image-20200412004042471

总结:

  • 通过checkout进行版本回退会造成游离的提交对象链,需要额外创建一个分支进行保存;

  • 因此,使用checkout进行版本回退的思路为,先切换到想要回退的提交版本,再删除进行版本回退的分支dev。最后,创建一个新的dev分支指向游离的提交对象链,完成分支dev的版本回退,简称"偷天换日";

  • 只要有分支指向,提交就不会被丢弃。

Ⅳ.revertreset的选择

由于checkout会造成游离的提交对象链,所以,一般不使用checkout而是使用resetrevert进行版本回退:

  • revert通过创建一个新提交的方式来撤销某次操作,该操作之前和之后的提交记录都会被保留,并且会将该撤销操作作为最新的提交;

  • reset是通过改变HEAD和分支指针指向的方式,进行版本回退,该操作之后的提交记录不会被保留,并且不会创建新的提交;

在个人开发上,建议使用reset;但是在团队开发中建议使用revert,特别是公共的分支(比如master),这样能够完整保留提交历史,方便回溯。

Ⅴ.回退方法汇总

版本回退主要有三大方式resetrevertcheckout,各方式的比较如下:

方法 效果 向前回退 向后回退 同步修改HEAD与分支指向
git reset --hard HEAD^ 往前回退1次提交
git reset --hard HEAD^^ 往前回退2次提交
git reset --hard HEAD~n 往前回退n次提交
git reset --hard <commit_id> 回退到指定commit id的提交
git revert HEAD 重做最新一次提交
git revert HEAD^ 重做倒数第二次提交
git revert HEAD^^ 重做倒数第三次提交
git revert HEAD~n 重做倒数第n+1次提交
git revert commit_id 重做指定commit_id的提交
git checkout commit_id 回退到指定commit id的提交

从上表可知,只有下列三种方式可以自由地向前向后回退:

复制代码
git reset --hard commit_id
git revert commit_id
git checkout commit_id

但是,使用checkout进行回退会出现游离的提交,需要创建一个新分支进行保存,所以不常用。

二、git stash

1.git stash的作用

git stash指令的作用为:对没有提交到版本库的,位于工作区或暂存区中游离的修改进行保存,在需要时可进行恢复。具体应用场景如下:

master分支进行两次提交:1st2nd,随后创建并切换到dev分支。在dev分支上进行一次提交(dev1),此时两分支的状态为:

image-20200412235844426

随后在dev分支上给文件test.txt添加一行dev2,但是不提交到暂存区,直接切换到master分支,会出现如下错误:

image-20200413001632846

图中显示的错误大意为:在dev分支上的修改会被checkout操作覆盖。下面我们来看看,将dev分支上的这一修改操作添加到暂存区后,再切换分支,是否还会出现同样的问题:

image-20200413001752227

可见还是会出现该错误,这初步验证了位于工作区和暂存区中的修改都会被checkout操作覆盖的结论。原因如下图所示:

image-20200413001917190

虽然在dev分支上修改了文件,但是没有将这一修改操作进行提交。这样就不会产生提交节点,就如上图所示,修改dev2是游离的,在切换分支的时候会被丢弃。

这种情况在日常开发中很常见,当在develop分支上开发新功能的时候,master分支出现紧急情况需要切换回去进行修复。但是,当前分支的新功能还没开发完全,贸然切换分支,原来开发的内容就会因被覆盖而丢失,怎么办呢?

有人可能会说进行一次commit不就可以了吗?确实可以。但是,这样不符合提交的代码就是正确代码的原则。更好的解决方法为使用git stash,如下图所示:

image-20200413002115302

可见git stash可以将当前dev分支上,位于在工作区或暂存区中的修改,在未提交的情况下进行了保存;并且将分支回退到修改前的状态,保存过后,就可以很顺畅地切换回master分支了。

图中的WIPworking in progress)表示的是正在进行的工作;

当我们在master分支上完成了工作,再次切换回dev分支时,查看test.txt文件:

image-20200413002256321

发现切换分支前所做的修改dev2消失了,这是为什么呢?

  • 其实,上面通过git stashdev分支上工作区或暂存区中的修改,提交到了stash区域进行保存,并将dev分支回退到修改前的状态。如下图所示:

    image-20200413003349365

  • 切换到master分支时test分支上的修改依旧会被覆盖。所以,再次回到dev分支时需要从stash区域中恢复切换分支前保存的修改;

怎样恢复通过git stash保存到stash中的修改呢?可以通过:

复制代码
git stash list

查看该分支上被stash保存的修改:

image-20200413224408623

继续给test.txt文件添加内容:dev3,并通过以下指令保存修改的同时添加注释:

复制代码
git stash save '注释'

image-20200413225024618

  • 首先,通过上述命令可以修改stash中存储修改的备注信息;
  • 其次,虽然在test分支上进行了两次修改,但是使用git stash保存修改后,文件test.txt并没有实际被修改;

2.恢复stash存储的修改

方法有很多,主要有以下三种:

git stash pop

image-20200413225140030

如图所示,通过上述命令将stash中存储的最新一次修改恢复了。相信你已经发现了,stash非常类似:先保存的修改,排在最后,序号最大;后保存的修改,排在最前,序号最小;

恢复了最新一次修改后,再次查看stash

image-20200413225221071

可以看到存储的修改只剩下一条了,由此可推断出git stash pop作用为:

  • 第一:恢复stash中存储的最新一次修改;
  • 第二:将该修改从stash中删除;
git stash apply

image-20200413225457480

如上图所示,使用该指令时发生了合并冲突。这是因为,stash中保存的每一次修改代表的都是一个版本。

image-20200413231349820

  • 如上图所示,在test分支上,进行第一次修改后,通过git stash将该修改作为修改0保存到stash中,此时分支中的文件并没有发生改变;

  • 进行第二次修改后,通过git stash将修改作为修改1保存到stash