Git - revert & reset

这一周在公司实习差点儿闯了祸,而且别人也遇到差不多的问题,总之这一周总是围绕着 revert 和 reset 转,趁这个节点,先穿插一些比较高级的 Git 命令,介绍一下 Git 中回滚的操作(统一用回滚不太恰当,但是这能表达操作的意思,也就不纠结了)。

定义:git-revert - Revert some existing commits
     git-reset - Reset current HEAD to the specified state

我们用圆圈表示一个提交,那么除了第一根提交之外(可以将多个引入一个版本库中,不过着暂时不重要),每一个提交都来自至少一个比它更早的提交 ,其中直接祖先称作该提交的父提交。那么可以预见的是,若某一提交存在多个父提交,它必由合并而产生。那么假设给定一个提交 C,Git 中我们用 ^ 表示 C 的父提交,则 C^1 表示 C 第一个父提,C^2 表示 C 第二个父提,那么可以理解,如果一个提交只有一个父提交,那它也只有 C^1,如下图
这里写图片描述
同时,我们用 ~ 表示 C 的一个祖先提交。C~1 是其第一个父提交, C~2 是其第一个祖父提交,C~3 是第一个曾祖父提交,以此类推。当在同一代中存在多个父提交时,紧跟其后的第一个父提交是第一个父提交。可以发现,C~1 和 C^1 表示同一个父提交。这两种表示法可以产生复杂的组合来表示任意祖先提交。如下图
这里写图片描述
回到主题,我们先产生3个 commit
这里写图片描述

接着输入
$git reset --hard 3c68146
(或者是
 $git reset --hard HEAD^1
 $git reset --hard HEAD^
 $git reset --hard HEAD~1
 $git reset --hard HEAD
 )

(ps:每次提交,Git 都会为对象库中的每个对象生成一个唯一的名称,这个名称是向对象的内容多内容应用 SHA1 得到的 SHA1 散列值。SHA1 的值是一个 160 位的数,通常表示为一个 40 位的十六进制数,如上图中 commit3 对应的散列值为 3c6814681bd684c7d004c7f4d529fd58dc5cfa0e 。有时候,SHA1 被简化成一个较小的、唯一的前缀,例如用

$git reflog

会看到散列值被简化为前 7 位的值,因为SHA1的特性,这7位数字已经足够区分一个对象了,同样的,在 reset 可以输入散列值的前 7 位定位头部,即3c68146)
得到输出:

HEAD is now at 3c68146 commit 2
此时,打印日志

这里写图片描述

也就是说头部重置到了第二次提交了,第三次提交被抛弃了(如果是误操作,那岂不是回不到 commit3 了?只要你记住第三次的散列值,你可以试试用同样的方法看能不能回去。那要是记不住怎么?我先剧透一下,之前也提到过,$git reflog 可以帮到你,不过这不是重点,以后我会再次提它)。同样的,如果我们此时 add commit4 将commit 添加到暂存区(stage)先不 commit 此时查看状态如下图

这里写图片描述

有明确提示,我们可以用
$git reset HEAD

回到未添加 commit4 到状态
顺便再补充一些知识,$git reset –hard 中的 hard 参数共有 5 个,分别为

[--soft | --mixed [-N] | --hard | --merge | --keep],

其中
A). –hard:重设(reset) index和working directory,自从以来在working directory中的任何改变都被丢弃,并把HEAD指向,可以理解为删除。
B). –soft:index和working directory中的内容不作任何改变,仅仅把HEAD指向。这个模式的效果是,执行完毕后,自从以来的所有改变都会显示在git status的”Changes to be committed”中,可以理解为保留这些更改到 暂存区(stage) 。
C). –mixed:仅reset index,但是不reset working directory。这个模式是默认模式,即当不显示告知git reset模式时,会使用mixed模式。这个模式的效果是,working directory中文件的修改都会被保留,不会丢弃,但是也不会被标记成”Changes to be committed”,但是会打出什么还未被更新的报告。
–merge –keep 不常用,先不做解释。
git revert 和 reset 的用法类似,这里我主要说明一下两者的区别:
git revert和git reset 在回滚这一操作上看,效果差不多。但是在日后继续merge以前的老版本时有区别。因为git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,导致这部分改变不会再次出现,但是git reset是之间把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入。

举个例子,比如说要回滚到的目标节点为 X,我们目前在 X + 2 这个节点上, +2 为期间所做的修改,git revert 用一次新提交回滚,也就是生成 X + 2 - 2 节点,而 git reset 是将 X + 2 删除 + 2。那这样的区别所带来的差异就是:当滚回到目标节点 X 后,在这个时你若要进行与之前相同的合并(merge)操作,revert 所产生但结果是 X 之后的变化都会被 2 - 2 覆盖掉,因此没有任何变化,X 还是 X;而 reset 则没有这样的副作用。

参考链接:http://guibin.iteye.com/blog/1014369
参考书籍:Git版本控制管理(第二版)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值