Situation

           <master>(previously deployed version)
    c1    /
----*----*         
     \\   c2             <feat1>(some feature branch)
      \\                /
       *----*----*----* c6
       c3   c4   c5    \\                  <some-fix>(just push by someone which caused an outage)
                        \\                /
                         *----*----*----*
                         c7   c8   c9   c10

某天,某地,某人把 some-fix 分支 push 到某代码仓库,代码仓库触发 CI/CD, CI/CD 的自动测试 Pipeline 通过,CI/CD 自动 build 源代码并且打包 build 过程生成的代码,部署到线上。

现在线上的应用出错,需要使线上部署的版本回退到 master 分支的最新提交那个版本,也就是 c2,求解法。

Analysis

从最新的提交开始,回退 (c2, c10] 范围的所有提交可以解决问题,但我们需要一个自动化一点的方案。git-rebase 子命令可以让 some-fix 变为基于 master 的分支。

Solution

在本地,先做:

git rebase --onto master feat1 some-fix

效果:

           <origin/master,master>(previous deployed version, 线上 master 分支)
    c1    /
----*----* c2                        <some-fix>(本地 rebase 后的 some-fix 分支)
          \\                         /
           *-------- .... *--------*
           c11'           c12'     cN'

git 会帮你把 some-fix 变基为基于 master 的分支,同时生成这些 c11’, c12’, cN’ 提交。

这样就将原问题化成了一个我们已知的问题。

然后再用一次 git-revert 子命令和 git-commit 子命令创建一个回滚提交:

git revert --no-commit master..some-fix
git commit -m "回滚 some-fix 分支到上一次 master 的提交"

然后再用一次 git-push 子命令把包含了新创建的这个回滚提交的 some-fix 分支再 push 一次到代码仓库即可使线上版本回滚到上一次 master 分支的那个版本。

Conclusion

我们使用 git-revert 子命令和 git-commit 子命令共同完成回滚提交的建立,然后用 git-push 子命令将回滚提交再次 push 到线上实现了线上部署的非破坏性回退。