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)

相关推荐
leoZ23119 小时前
Git 集成实战完全指南(四):Git 冲突解决
大数据·git·elasticsearch
枫荷1 天前
Git LFS 大文件优化说明
git
techdashen1 天前
不用再反复 stash:用 Git Worktree 同时开发多个分支
大数据·git·elasticsearch
leoZ2312 天前
Git 集成实战完全指南(八):团队协作最佳实践
git
晴雨天️2 天前
Git工具使用指南
笔记·git
酷可达拉斯2 天前
Linux操作系统-简单内核优化
linux·git·php
触底反弹3 天前
🔥 Git 从零到精通:彻底搞懂核心概念与工作原理
git·面试·开源
tokenKe3 天前
Epic Games 发布下一代版本控制系统 Lore:被 HN 干到 1000+ 分的“游戏版 Git“
git·游戏
Eira-Z3 天前
git(持续学习中...)
git·学习
leoZ2313 天前
Git 集成实战完全指南(五):Git Blame 与历史追踪
大数据·git·elasticsearch