结论

开发流程中,不免会遇到需要回滚 master 代码的时候。关于如何回滚,我们将统一采用 revert 方式进行回滚,以保留之前错误的提交,便于进行复盘与 CR

回滚步骤如下

  1. git checkout master —— 分支切换到 master
  2. git pull —— 更新 master 代码为最新
  3. 从 master 分支中开一个 feat 分支
  4. git log —— 查询提交记录,并找到需要回滚的 commit id
  5. git revert 或者 git revert -m 1 faulty merge —— 回滚
  6. push & 提交与 master 分支的 mr

Checkout、reset、revert 的择决

Checkout

git checkout 是一种便捷的方式,来将快照「解包」到你的工作目录上去。 git checkout 可以检出提交、也可以检出单个文件甚至还可以检出分支

1
git checkout commitId

检出 commitId 对应的提交,你会发现当前工作目录和commitId完全一致,你可以查看这个版本的文件编辑、运行、测试都不会被保存到git仓库里面。你可以git checkout master 或者 git checkout -回到原来的工作状态上来

Reset

git reset 有很多用法

1
git reset <file>

从暂存区移除特定文件,但不改变工作目录。它会取消这个文件的缓存,而不覆盖任何更改

1
git reset

重置暂存区,匹配最近的一次提交,但工作目录不变。它会取消所有文件的暂存,而不会覆盖任何修改,给你了一个重设暂存快照的机会

1
git reset --hard

加上--hard标记后会告诉git要重置缓存区和工作目录的更改

1
git reset <commit>

将缓存区重设到这个提交,但不改变工作目录

1
git reset --hard <commit>

将当前分支的指针 head 移到对应的 commit id 提交

Revert

git revert被用来撤销一个已经提交的快照。和 reset 是完全不同的。实质是在最后加上一个撤销了更改的新提交,而不是从项目历史中移除这个提交

1
git revert <commit>

生成一个撤消了,引入的修改的新提交,然后应用到当前分支

img

1
2
3
4
5
6
7
8
9
10
11
12

81f734d commit after bug
|
3a395af bug
|
3aa5dfb v3 (<- HEAD)
|
5aab391 v2
|
ff7b88e v1
|
95d7816 init commit

我们在3a395af 引入了一个 bug,我们明确是由于3a395af造成的 bug 的时候,以其我们通过新的提交来 fix 这个 bug,git revert , 让他来帮你剔除这个 bug

1
git revert 3a395af

得到结果

1
2
3
4
5
6
7
8
9
10
11
12
13
cfb71fc Revert "bug"
|
81f734d commit after bug
|
3a395af bug
|
3aa5dfb v3 (<- HEAD)
|
5aab391 v2
|
ff7b88e v1
|
95d7816 init commit

这个时候 bug 的改动被撤销了,产生了一个新的 commit,但是commit after bug没有被清初。

所以相较于resetrevert不会改变项目历史,对那些已经发布到共享仓库的提交来说这是一个安全的操作。其次git revert可以将提交历史中的任何一个提交撤销、而reset会把历史上某个提交及之后所有的提交都移除掉

回滚错误的 merge

当一个有 bug 的分支 merge 进 master 后,且后续多个开发分支建立在该 merge 之后,将会给后续开发分支带来 bug,导致其余同学测试跑不通或者线上问题。

1
2
3
4
5
6

init -> v1 -> v2 -> v3 -- faulty merge -> v4 -> vc3 (master)
\ \ / /
\ d1 --> d2 --> d3 --> d4 (feat)/
\ /
c1 --> c2 -------------------c3 (other)

此时第一想到的应该是回滚掉错误的提交

1
git revert -m ``1` `faulty merge

-m后面带的参数值 可以是 1 或者 2,对应着 parent 的顺序.上面列子:1 代表v3,2 代表d2 所以该操作会保留 master 分支的修改,而撤销 feat 分支 merge 过来的修改。

提交历史变为

1
2
3
4

init -> v1 -> v2 -> v3 -- faulty merge -> v4 -> vc3 -> rev3 (master)
\ /
d1 --> d2 --> d3 --> d4 (feat)

此处rev3是一个常规 commit,其内容包含了之前在faulty merge撤销掉的 feat 合并过来的 commit 的【反操作】的合集。

恢复之前的回滚

把之前 master 带有【反操作】的 commit 给撤销掉

1
git checkout master``git revert rev3``git merge feat

此时提交历史变成了

1
2
3
4

init -> v1 -> v2 -> v3 -- faulty merge -> v4 -> vc3 -> rev3 -> rev3 -> final merge (master)
\ / /
d1 --> d2 --> d3 --> d4 --------------------------------(feat)