git版本回退介绍

972 阅读4分钟

一、 git revert的用法

git revert 的作用是通过创建一个新的版本,这个版本的内容与我们要回退到的目标版本一样,但是HEAD指针是指向这个新生成的版本,而不是目标版本。
如果我们想恢复之前的某一版本(该版本不是merge类型),但是又想保留该目标版本后面的版本,记录下这整个版本变动流程,就可以用这种方法。
我们使用git revert HEAD命令就可以创建一个新的版本,此版本与上一个版本相同。

 - git revert HEAD :撤销前一次 commit

 - git revert HEAD^:撤销前前一次 commit

以git revert HEAD^为例,执行前:

执行后,相当于现在的版本是提交了test4之后的版本:

再执行一次git revert HEAD,相当于现在的版本是提交了solve conflict之后的版本:

二、 git reset 的用法

1、git reset --hard HEAD^

更改了common.h文件,里面加了一句话“over write”,然后add和commit,如下(作为起始条件图)。

执行git reset --hard HEAD^,回退到上一个版本。这里的回退指的是已经commit,或者已经add但未commit,或者尚在工作区未add的内容都要回退,版本文件中commit了的、add未commit了的以及仍处于编辑状态的内容都将被删掉。注意是删掉而不是退到工作区!

当git reset –hard HEAD^后,如果又想回到后面一个版本,但是苦于看不到后面版本的commit ID号,这时可以利用git reflog命令,示例如下。

reset前:

reset后:

从上面reset后可以看到,HEAD到了test5上面(但是后面的test4、merge直到test2都没了,暂时不知道什么原因,可能跟merge操作有关,具体后续研究)。下面输入命令git reflog就可以看到被reset的commit ID号。

然后执行git reset –hard 9b99287就可以回到原来的状态,而且丢失的test4、merge直到test2也都回来了。

有些时候,当把一个文件add进stage中后(没有commit),如果想回到原来的状态,可以利用git reset –hard HEAD(不加^)的方式进行。如下所示。

对于一个已经add但是没有commit的文件,执行命令git reset会撤销add操作,让该文件回到工作区,且该文件中的内容不会变化。但是如果执行git reset –hard HEAD操作,则会在撤销add操作的同时丢弃文件中的修改内容,所以要谨慎!

2、git reset --soft HEAD^

执行git reset --soft HEAD^(同样是更改了common.h文件,里面加了一句话“over write”,然后add和commit,即在起始条件图的基础上),将commit到repository中的内容回退到stage中。这个命令执行后的示意图和上面hard reset后的图一样,只是“over write”还在文件中,文件处于add但未commit的状态。如果之前commit后又进行了add但是没有再次commit,则soft reset后,被退回到stage中的commit了的内容可能会影响到后面add的内容(如果两者有冲突)。当然,同样也可能影响到目前尚处于编辑状态的工作区中的内容如果两者有冲突的话。

3、git reset --mixed HEAD^

执行git reset --mixed HEAD^(同样是更改了common.h文件,里面加了一句话“over write”,然后add和commit,即在起始条件图的基础上),将commit到repository中的内容回退到工作区中,同样存在着冲突问题。

可以用下面的图来表示hard、soft、mixed三种reset的关系。

但是值得注意的一点是:不管是revert还是reset,在回退版本的过程中,都不会造成'detached HEAD' state状态(该状态会在git checkout时产生,例如:git checkout 9c20a2c)。

三、 get checkout用法

上面git reset回退时直接将整个仓库的版本进行回退,而利用git checkout可以回退某个文件。

回退前:

3d25475版本的a.c的内容是“#this is a.#make a comment.”, ed482a4版本的a.c的内容是“#this is a.”。假如要回退a.c文件到ed482a4,而b.c文件保持不变,可以采用下面的命令(--的两边都有一个空格):

     git checkout ed482a4 -- a.c

命令执行后:

可以看到log信息并没有发生变化,但是本地a.c文件的内容变成了“#this is a.”,而b.c的内容没有发生变化。另外,整个仓库的版本仍然是3d25475.