概述
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合并进来。