需求分支首先通过MR合并到了master分支,部署后发现有问题,于是回滚代码,操作了MR处的revert,后面修复了问题,使用原功能分支提新的MR时,发现变更处是空的,本文来解决此类无法合并情形的问题。
首先说结论:对原MR的revert再次revert,后续即可使用原功能分支合并到主干分支。
分析过程以及原因详见下文。
背景
20240311晚,有个需求上线后发现有问题,于是回滚了部署资源,同时需要回滚代码。
回滚代码使用的是gitlab MR处的revert:
 
上线范围包含了两个功能分支:
- a
- b
其中a分支的内容需要回滚,b分支原先合并到了a分支。需要将b分支的内容重新合到master,进行部署上线。
使用b分支提MR到master时,发现不显示一行变更,即MR无法正常操作。
revert操作后,会提交一个新的commit,用来表示前面的mr被回退。
该团队该项目git协作使用的是功能分支完备后
merge到主干分支的方式。
分析
操作关键步骤
我们对上面的问题进行简化,在本地环境开启新的分支进行模拟:
- test-mr-revert模拟功能分支;
- master-bak-20240312模拟主干分支;
1. 开发功能
在 test-mr-revert 上提交一些commits。
2. 使用MR合并 test-mr-revert 到 master-bak-20240312
MR会生成一个新的标识merge的commit。
3. 进入刚刚的MR,点revert
revert 后创建了一个分支,其中新增了一个commit,回退了之前的MR,之后会提交一个新的MR,将revert对应commit合并到master-bak。
4. 再次合并 test-mr-revert 到 master-bak-20240312
此时复现了我们上线时的情形:
 
找根因
Google搜索「git revert merge and remerge」,找到了StackOverflow上的一个问答:
https://stackoverflow.com/questions/1078146/re-doing-a-reverted-merge-in-git
08、09年的时候就有人提出了这种情况的疑问。
对应官方 git-scm 回退一个有问题的merge文档:https://mirrors.edge.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty-merge.txt
我贴一下官方文档中的关键解释:
 
小结一下这种情况的原因:
- revert操作后,会提交一个新的- commit,用来表示前面的- mr被回退。
- 产生的影响就是,生成了新的revert commit,保留了原来功能分支上的commit。由于这个revert记录了操作了某些commit的回退,所以用原始功能分支上的commit操作merge,会没有变更。
因此问题根因就是,针对MR的revert,会将功能分支的所有commit标记为回退,因此再往主干分支合并时会不生效。
针对整个过程画了个图,帮助读者更好理解:
 
解决方案
官方文档给出了解法:对前面的revert,进行一次revert操作。这种解法有一个前提是,功能分支问题已修复。
针对我们11号上线的情况,由于我们其实是把两个功能分支合并到了一起,所以提了一个统一的MR,针对MR操作revert后,两个功能分支上的commit其实都会被标记为回退。因此针对此类情况,之后可以不合并两个分支,多个分支可以多次提交MR,这样针对MR回退时,多个分支间不受影响。
另外在对commit的管理足够规范前提下,如果commit提交足够原子性,并且数量可控,在对一个融合的MR,可以考虑使用cherry-pick,这样可以完成我们一个MR中仅保留部分commit的目的。
