是五月呀!

git回滚

1.git revert

1
git revert <commit>

命令的含义是:

Given one or more existing commits, revert the changes that the related patches introduce, and record some new commits that record them. This requires your working tree to be clean (no modifications from the HEAD commit).

Note: git revert is used to record some new commits to reverse the effect of some earlier commits (often only a faulty one).
If you want to throw away all uncommitted changes in your working directory, you should see git-reset, particularly the --hard option.
If you want to extract specific files as they were in another commit, you should see git-checkout, specifically the git checkout <commit> -- <filename> syntax.
Take care with these alternatives as both will discard uncommitted changes in your working directory.

这里解释的很清楚,revert命令会撤销某一次提交引入的修改,并且会产生一次新的提交。
下面的Note部分对reset、checkout做了区分:
如果你想把工作区没有提交的修改扔掉,那么使用

1
git reset --hard

如果你想检出某一次提交版本的文件,那么使用

1
git checkout <commit> -- <filename>

对于revert命令,需要注意一点,如果使用下面的命令:

1
git revert HEAD~1

那么只会撤销上上次这一次提交的修改,而不会撤销上次提交的修改。它并不是回退到HEAD~1前的版本。
举个例子:
假如现在有三次提交:

1
2
3
* c5ce0d0 (HEAD -> master) c - damon4u, 9 seconds ago
* 131ffaa b - damon4u, 25 seconds ago
* d8f0aa0 a - damon4u, 33 seconds ago

然后执行:

1
git revert HEAD^

撤销上上次的修改,执行后会让我们写备注信息,从这里我们可以看到,这次revert会撤销131ffaa这次修改,这次撤销会删除b。
注意,只删除了b,没有说删除c,也就是说,上次的修改是不会收到影响的,不会回到a那次提交。

1
2
3
4
5
6
7
8
9
10
Revert "b"
This reverts commit 131ffaa420d3e27dddc10caa3a089fb8679c034a.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
# deleted: b
#

再看一下日志:

1
2
3
4
* 16481c1 (HEAD -> master) Revert "b" - damon4u, 3 minutes ago
* c5ce0d0 c - damon4u, 4 minutes ago
* 131ffaa b - damon4u, 4 minutes ago
* d8f0aa0 a - damon4u, 5 minutes ago

多了一条回滚的提交。

线上推荐使用revert来撤销最近一次提交,回滚到上一个版本,因为不会影响历史记录,只是新增一次提交,比较安全。
但是如果要回滚到指定commit,那么可以使用reset命令或者checkout命令,下面介绍。

2.git reset

1
git reset [<commit>]

This form resets the current branch head to <commit> and possibly updates the index (resetting it to the tree of <commit>) and the working tree depending on <mode>. If <mode> is omitted, defaults to “--mixed“. The <mode> must be one of the following:

这里解释的也比较明白,使用reset命令可以将当前分支的HEAD指向某一次提交,并更新当前的工作区到那次提交,mode模式跟之前撤销工作区修改时一样,默认是–mixed,即恢复到add后,没提交前。

还用上次的例子:
我们先把b请回来:

1
git revert HEAD

这个命令是撤销上一次提交,还记得,上次提交把b删了,那么撤销它,就能把b找回来。

假如我们发现b和c都没有用,想回到只有a的时候,那么先在日志中找到只有a的那次提交SHA值d8f0aa0,然后执行:

1
git reset d8f0aa0

这样,就只有a了,并且历史也被我们篡改,看不到b和c的提交历史啦。
所以说,这样做还是很危险的。适合本地操作。
如果想找回b和c怎么办呢?
先找到包含bhec的SHA

1
git reflog

1
2
3
4
5
6
7
8
d8f0aa0 HEAD@{0}: reset: moving to d8f0aa0
0bc9d5a HEAD@{1}: revert: Revert "Revert "a""
97adb10 HEAD@{2}: revert: Revert "a"
c972a81 HEAD@{3}: revert: Revert "Revert "b""
16481c1 HEAD@{4}: revert: Revert "b"
c5ce0d0 HEAD@{5}: commit: c
131ffaa HEAD@{6}: commit: b
d8f0aa0 HEAD@{7}: commit (initial): a

也就是c5ce0d0
然后执行:

1
git reset c5ce0d0

就找回了b和c。