问题描述

要上线了 master 分支 merge feature分支,后上线

  1. git checkout master
  2. git merge origin/feature

此时发现feature分支代码有问题, master 就revert此次merge (紧急回滚上线)
(野路子操作,正规线上回滚操作流程 应该是每次上线打个tag,想回滚直接部署前一个tag)

  1. git revert < commit id > -m 1

在feature 分支把问题修复后,master分支再次merge feature分支

  1. git merge origin/feature

问题出现了 第一次merge的代码在master里”消失了”,再怎么merge 都无法merge上
原因: 因为git第一次merge此分支了, revert 只是在此分支上提交了一次”反向修改”(相当于 新的commit). 这merge和revert 这两次都相当于commit

解决方法:

有三个办法:

1. 强制物理覆盖重新提交一次

此法暴力解决一切git问题…
操作方法: 从master拉个新分支出来,物理拷贝feature分支代码后提交, master再merge此分支

2. master 分支reset 后 pull -f

注意:一般master分支都有protect ,不让回滚提交,要去gitlab上关闭此保护 (所以此法适用于非master分支)

  1. git checkout master
  2. # 把master回滚merge之前的状态
  3. git reset head^ --hard
  4. (或 git reset --head "<>")
  5. # 强制推上去
  6. git push -f
  7. # 重新merge feature后再推远程即可
  8. git merge feature
  9. git push

git reset head^ —hard : head^表示回滚到上一个提交版本 —head 本地代码会被覆盖

3. 对 revert 的那次提交记录再次进行revert (官方推荐方法)

见: https://stackoverflow.com/questions/19379034/force-merge-after-reverting-merge-commit-int-git
具体操作方法:

  1. git checkout master
  2. # 从master拉一个新分支 revert_tmp
  3. git checkout -b revert_tmp
  4. # 找到 revert 的那条提交记录,注意了,revert 相关的会有两条记录,第一条是 revert,第二条是 revert 后 merge 的记录,这里取第一条
  5. # 用revert_tmp分支revert之前的revert
  6. git revert <版本号>
  7. # 再用master分支合并此分支代码推到远程即可
  8. git checkout master
  9. git merge revert_tmp
  10. git push

这样代码就都回来了
当然也可以直接在master 上revert 之前revert的分支即可(不用新拉分支), 但是注意解决好冲突

原理和拓展

回滚操作中: git revert 和 git reset的区别:

  1. git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit。
  2. git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容。
  3. 在回滚这一操作上看,效果差不多。但是在日后继续merge以前的老版本时有区别。因为git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,导致这部分改变不会再次出现,但是git reset是之间把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入。