git revert后再次merge到master会丢失部分代码的问题

提前声明,这个问题你在公司可能一辈子碰不上,只有很多野路子协同开发可能会遇到这个问题。不过,这个对于理解revert的本质确实很有帮助。

一、实验复现问题

在feature分支上开发了一个新功能,其中有部分带点bug

恰巧,代码评审时没有发现这个问题,将这个feature开发的新功能合并到了master上

自然而然的,master在线上运行的过程中出现了问题,这个时候我们选择了通过revert回滚

按照正常流程,有bug就要修复,于是在feature上修复了这个bug

经过更加严格的代码评审,这个代码没问题,于是又将修复后的feature合并到了master
这个时候问题出现了,master上feture1和feature2的文件没有了,仅留下feature3

二、分析下问题如何造成的

在我们将feature的修复代码合并到master之前,masterfeature的分支如下:

graph LR init --> feature feature --> D[revert feature]
graph LR init --> feature --> fix

此时按照常理来说,合并时会进行差异检查 。两个分支会因为revert featurefix两个commit出现了冲突需要进行合并。但是,事实上并没有。

非常反直觉的是,在操作合并时revert feature这个记录像失效了一样,fix直接合并了上来。

此时fix仅变更了含有bug的feature3revert feature没有任何fearue的部分

三、出现问题的原因

对此,Linus早就给出了解释:

Reverting a regular commit just effectively undoes what that commit did, and is fairly straightforward. But reverting a merge commit also undoes the data that the commit changed, but it does absolutely nothing to the effects on history that the merge had.
So the merge will still exist, and it will still be seen as joining the two branches together, and future merges will see that merge as the last shared state - and the revert that reverted the merge brought in will not affect that at all.
So a "revert" undoes the data changes, but it's very much not an "undo" in the sense that it doesn't undo the effects of a commit on the repository history.
So if you think of "revert" as "undo", then you're going to always miss this part of reverts. Yes, it undoes the data, but no, it doesn't undo history.

简单的梳理下:

  1. 我们在feature分支上revert一个常规commit,就仅仅是撤销这个commit做的改动
  2. 但是如果我们在master分支上revert一个merged commit(合并上来的commit),也仅仅撤销这个commit的改动,而不会对master分支产生任何对这个merge状态的影响
  3. 这就意味着意味着在master分支上merge feature的状态仍然存在
  4. 我们在feature修复后再发起merge,检查时会看到master分支上存在merged状态
  5. 因此只会带上merge状态之后(也就是feature之后)的改动,即fix之前被revert的改动(即feature)不会再被merge到master分支上

最后总结下核心原因:revert撤回了代码的变更,但是没有撤回合并的记录,在master分支上慎用此方法。

四、如何解决这个问题

  1. 在master上复原feature的改动 ,也就是revert revert feature, 让master和feature分支上的代码一致,然后再进行合并。
graph LR init --> feature feature --> D[revert feature] D[revert feature] --> E[revert `revert feature`]
graph LR init --> feature --> fix
  1. 在feature上同步master,然后在进行修复,最后合并也能解决这个问题。

这就是为什么这个问题很难在公司遇到的原因,正经人谁不先看一下master直接提merge啊。但是这样也会把feature分支上有用的代码全部弄没。

graph LR init --> feature feature --> D[revert feature]
graph LR init --> feature --> D[revert feature] --> fix
  1. 虽然,revert没有撤回合并的状态,但是那个合并的状态绑定的是原有的commit ID,我们可以从feature将原commit的内容带到master,但是需要产生和原merged commit不同的状态(不同的commit SHA ID)

在feature分支reset + commit,产生新的commits:feature-copy 修复后再merge到master

graph LR init --> feature feature --> D[revert feature]
graph LR init --> feature-copy --> fix

参考文章

Git revert 某次merge后再重新 merge代码被丢失(第一次想merge的代码再也merge不上了)_git revert 后 再merge-CSDN博客

git 分回滚后无法合并代码问题 - 赵坤坤 - 博客园 (cnblogs.com)

如何再次合并已经被revert的合并? | furthergo

git撤销merge,彻底学会git revert的用法 - 我的诗和远方 - 博客园 (cnblogs.com)

相关推荐
int WINGsssss3 小时前
Git使用
git
用户0760530354385 小时前
Git Revert:安全移除错误提交的方式
git
Good_Starry17 小时前
Git介绍--github/gitee/gitlab使用
git·gitee·gitlab·github
云端奇趣1 天前
探索 3 个有趣的 GitHub 学习资源库
经验分享·git·学习·github
F_D_Z1 天前
【解决办法】git clone报错unable to access ‘xxx‘: SSL certificate problem:
网络·git·网络协议·ssl
等风来不如迎风去1 天前
【git】main|REBASE 2/6
git
艾伦~耶格尔1 天前
IDEA 配置 Git 详解
java·ide·git·后端·intellij-idea
云兮杜康1 天前
IDEA中用过git之后文件名颜色全变红
java·git·intellij-idea
睡不醒的小泽1 天前
git merge 和 git rebase
git
艾伦~耶格尔1 天前
Git 下载及安装超详教程(2024)
git·gitee·码仓