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)

相关推荐
轮到我狗叫了1 天前
git - 版本控制工具 - 对应的常见命令 - 以及无需后续每次手动source conda
git
changxiang1 天前
GIT 备忘
git
DogDaoDao1 天前
Windows 开发提效工具全景指南:60+ 工具的工程化分层配置
windows·git·程序员·开发工具·powershell·everything·msys2
wdfk_prog2 天前
GitHub push 失败:如何扫描并清理 Git 历史中的大文件
git·elasticsearch·github
大明二代2 天前
使用 Traefik、cert-manager 和 DNS-01 为内网 Kubernetes 服务配置 HTTPS
git·kubernetes·flux
小芒果_012 天前
git常用命令速查
大数据·git·elasticsearch
2501_930472442 天前
腾讯云助手规范化Git提交记录
git·elasticsearch·腾讯云
风尘小子2 天前
git的.gitignore文件中文件和目录配置
git
Tanner_SL3 天前
Linux笔记之GIT常用命令
linux·git
醉颜凉3 天前
Jenkins与Git集成完全指南:从基础配置到自动触发构建
运维·git·jenkins