15-git-11-revert

概述

git revert命令用于撤销某个具体的commit。

git revert <commitID>

撤销上一个commit,之后推送到远程

git revert HEAD

实例

当执行完git revert <commitID>,会出现vim编辑器页面,按:q退出编辑,然后提交该commit

revert和reset的区别

reset(重置):将版本回退到某个commit

恢复(revert): 回滚某个具体的commit,将它撤销

参数

先说一个场景,普通的commit可以直接用revert回滚,假如是一个合并的commit呢

普通commit

git revert <commit-id>

合并commit

git revert <commit-id> -m

-m

当一个commit有两个父节点时,git并不知道你想要回滚它与哪个父节点之间联系,所以需要我们帮git确定保留哪一个。这时需要指定一个 parent number 标识出"主线",主线的内容将会保留,而另一条分支的内容将被revert。

即m的意义为指定要保留的父节点。

以下图中为例:

我们可以看到合并的节点为bd86846

使用 git show 命令可以查看 commit 的详细信息

git show bd86846
---
commit bd868465569400a6b9408050643e5949e8f2b8f5
Merge: ba25a9d 1c7036f

Merge: ba25a9d 1c7036f代表该 merge commit 是从 ba25a9d 和 1c7036f 两个 commit 合并过来的。

普通的commit是没有merge这一行的。

从图中可以看出,ba25a9d 代表 master 分支,1c7036f 代表 will-be-revert 分支

-m 选项接收的参数是一个数字,数字取值为 1 和 2,也就是 Merge 行里面列出来的第一个还是第二个。

我们要保留主分支上的内容,所以应该指定为1

git revert -m 1 bd86846

需要注意的地方

小明从节点A拉了一条dev分支出来,在节点B中新增了一个文件http.js,并且合并到master分支,合并节点为E。这个时候发现会引起线上bug,赶紧撤回这个合并,新增一个revert节点E’。过了几天小明继续在dev分支上面开发新增了一个文件main.js,并在这个文件中import了http.js里面的逻辑,在dev分支上面一切运行正常。可当他将此时的dev分支合并到master时候却发现,http.js文件不见了,导致main.js里面的逻辑运行报错了。但这次合并并没有任何冲突。

根据Git的合并策略,在合并两个有分叉的分支(上图中的D、E‘)时,Git 默认会选择Recursive策略。找到D和E’的最短路径共同祖先节点B,以B为base,对D,E‘做三向合并。B中有http.js,D中有http.js和main.js,E’中什么都没有。根据三向合并,B、D中都有http.js且没有变更,E‘删除了http.js,所以合并结果就是没有http.js,没有冲突,所以http.js文件不见了。

即你之前被合并的分支上的提交,都会被丢弃,但是新增的提交,会保留下来。

解决办法:

1、revert节点E’之后,此时的dev分支要抛弃删除掉,重新从E’节点拉出分支继续工作,而不是在原dev分支上继续开发节点D;

2、在节点D合并回E’节点时,先revert一下E’,将之前丢弃的合并提交都找回来,然后再将节点D合并进来。

参考

segmentfault某作者

李泽帆