版本回退

51 阅读9分钟

同学们好,我们将在视频中讲解git的重要能力之一即版本回退功能。之前的课程中我们提到git是版本控制系统,它能够管理文件的历史版本。在进行版本回退实操之前,我们先了解或者回忆一下版本回退的含义。以之前的例子为例,如果你的老板想让你撰写一个设计文档,而你已经撰写了5版设计文档,当你撰写完第五版设计文档发给老板时,你的老板说:你这个版本的文档不如第一版的文档写得好,也不如第一版的文档符合我的预期,你把第一版的文档发给我。

image.png

由于你对一个文档进行了多个版本的维护,因此你可以将设计文档的第一个版本发送给你的老板,我们将v5版本回退到v1版本,这个过程我们称之为版本回退。它使用的是一个git reset命令,这是本节视频重点讲述的命令。

接下来将其粘贴到我们的板书上。关于命令,我们需要以实际操作为例。我们来查看当前目录下的readme文件,它目前状态有两行代码,一个是hello git,一个是hello world。我们不要忘记,在创建readme时,它里面只写了一行代码,也就是一个hello git。

我们第二次修改新增hello world,因此对于readme文件而言,它有两个版本。我们将这两个版本都书写在板书上。

Readme文件的第一个版本只有一个hello git,我们在这里简单写一下git。第二个版本里除了git,我们新增了一个word。我们把这两个版本进行标注。

接下来我将向大家介绍git reset的本质。reset是用于回退版本的,其本质是将版本库中的内容进行回退,回退不同版本的内容。我们之前已经跟大家明确过几个概念,除了版本库,还跟大家讲过工作区、暂存区以及最后的版本库。对于目前阶段,即当前的readme而言,readme的工作区目前有Hello git和Hello word两行代码。对于暂存区而言,由于我们add,暂存区的readme文件也有Hello git和Hello word。版本库同样如此,我们进行过commit操作,它里面也有git以及word。

如果我们想要对readme文件进行一次回退,就需要使用git reset命令。git reset本质回退的是版本库中的内容,即我们回退一次需要使用一次git reset,即将版本库中的Hello git和hello world回退到hello git只剩一行。

工作区和暂存区的内容会回退吗?取决于git reset三个选项。我们将向大家解释这三个选项的含义。首先写第一个soft选项,这三个选项在课件上的含义都在这里,大家可以先阅读。文字不好看,我们画一个表格与大家详细区分。

如果我们使用soft选项,那么只回退版本库中的内容,对于暂存区和工作区中的内容不进行回退。

接下来我们讨论第二个mixed。如果我们使用mixed选项,那么对于版本库的内容肯定会进行回退,因为本质是回退版本库中的内容。如果使用mixed,那么对于暂存区的内容也会进行回退,只是它不会将我们工作区中的内容进行回退。工作区还是两行,一个是git,一个是word。

接下来是第三个选项hard。Hard会回退所有区域内容,工作区、暂存区和版本库都是要回退到git的。

我要告诉大家mixed是一个默认选项,如果我们不使用任何选项,它默认使用该选项。

image.png

我们了解对应选项的含义之后需要向大家说明注意点。既然我们了解了它们的含义,对于hard选项,我们需要慎用的原因是什么?如果使用hard,那么对于版本库暂存区和工作区中的内容全部会回退掉,这会导致什么问题?

如果我正在工作区中的readme进行开发,并且新增一行工作区中的bite,一旦回退,就会全部替换掉新写的bite。我们怎么样都找不回新开发的代码了,对开发人员来说是非常头疼的,可能写了几天的代码,一旦使用hard来回推,代码就会消失不见,因此我们要慎用hard。接下来我们将以hard的方式向大家演示。

我们讲述对应命令之后,打开终端使用git log查看历史日志。我们可以看到之前已经多次提交,最新的一次是修改Readme,也是新增hello world,最早的一次提交就是add first file,这次提交创建了一个Reading并且新增hello git。如果我们想要退回到只剩一个hello gift版本的Readme,就可以使用git reset。

接下来我们将向大家演示hard。如果我们想要回到这个版本提交,那么我们将其commit ID复制过来,并在reset后重新复制粘贴。回车后我们可以看到已经打印了一个日志,并且已经成功回去。接下来我们查看当前目录下有哪些内容,发现当前gitcode下只剩下一个readme,之前的file1到file5就消失了。

我们使用hard将工作区也回退了。我们的file1到file5都是经过add first file后面才提交,一旦回退到这一次,后面的提交都会被回退,因此file1到file5也不见了。接下来我们需要打印readme中的内容,这个readme就是我们工作区的内容,查看他是否回退成功。

image.png

我们看到只有一个Hello git,Hello world已经消失,这证明我们的回退操作确实成功。我们再打印对应的log,发现这次的log只剩add first file后面的log都消失了。对于回退操作,通常情况下演示结束,有些同学突然后悔该怎么办?

如果我后悔了,那么我是否可以回到这种情况?答案是可以的。我们需要使用reset的命令,reset --hard。我们将所有区域都进行回退,我们之前打印过这一行代码,有对应readme的commit ID,我们直接将这个commit ID拿过来进行回退。回车之后我们再来看当前目录下file1到file5它都回来了,并且我们再来看readme里面hello world也回来了。

image.png

我们查看对应的log并且打印log。我们发现log已经回来了,master最新的是最近一次提交的modify readme的commit ID。我们之前已经向大家证明,大家有后悔药可以吃,是因为当前终端并未将modify readme的commit ID清除掉。

image.png

我们再次hard回退到第一次版本。回退之后,我们现在清理屏幕或者有些同学可以关闭服务器,这种情况下我们再查看log。

我们发现之前的commit ID已经不见,最新的一次是hello world的提交也已经不见。我们无法获取对应的commit ID,怎么回退呢?答案是仍然可以查询commit ID,我们使用了一个命令git reflog。

这个git总是有后悔药可以吃,我们来看一下对应的内容。

reflog的命令用于记录本地的每次提交命令。我们可以查看对于第一次提交,他已经将我们最早的提交放到这里。git first add first file、add 3 file、add file、add file 5以及modify readme都有记录,包括中间几次操作的回退指令也被记录下来。因此git reflog可以用于记录我们本地的每次提交命令。

image.png 我们主要查看modified readme,在modified readme之前有一个999cead,它是我们这次的commit ID的一部分,虽然它这么短,但是我们仍然可以使用一部分的commit ID来回退,如何回退仍然使用git reset --hard。我们把短的拿过来粘贴一下,然后再打印一个log,重新来一遍git log。

我们发现确实回退到modify readme,同样我们还需再打一下readme里面确实还有Hello world,表示我们回退成功了。在这样的前提下,我们只有找到commit ID才能吃后悔药。在开发过程中,我们会进行很多git操作,迟早会把commit ID冲掉。一旦找不到commit ID,就没有后悔药可以吃了。

image.png

我们向大家介绍了git版本回退的操作。我们刚才可以看到版本回退速度非常快,我们要解释一下为什么版本回退速度快的原因。在我们的课件上画了一张图,这张图表示我们现在的图与之前有些差异,我们需要重新画一下。最新的一次提交是git以及word,上一次提交就是一个git,我们就这样画。

image.png

我们可以看到git中有head指针指向master,实际上存放的是一个commit ID。这个commit ID是一个git对象,git对象里面包含git以及word。如果我们进行版本回退,那么会将这个状态变成什么样子?我们将它拿下来,它直接修改指针指向的内容,不指向我们最新的一次提交,而是指向这次提交。

实际上是修改master的内容,只修改这个commit ID。我们吃后悔药时想从git再到git加word,这种情况只需修改master里面的commit ID 即可完成回退。

image.png