git revert

最近一直在 github 上提交代码,所以总会遇到提交的代码 broken 了之前的 function。

Perhaps you didn’t have enough coffee that morning, or it was just before lunch.

其实这还无关紧要,再提交一个修复下就可以了。 但是也会遇到比较头疼的, 比如:

注意蓝色这条线的 merge 那个点,开发同学因为粗心忘记把自动 merge 的代码提交了。
黑色这条线的同学,如果 pull 下来,就会发现一部分代码回到了蓝线的起点时候的状态。
然后呢,黑线这边的 merge 就会导致部分代码 rollback 了。很悲催吧。这个时候呢,提交修复也不太可能,最好的办法就是 revert 了。

概念

git revert 命令撤销一个 commit。它的做法是提交一个新的 commit, 这个 commit 里面将你要回滚的 commit 的修改全部撤销。
所以它不会破坏你的历史。如图所示:提交一个新的 commit (蓝球), 撤销灰球修改。

Usage

1
git revert <commit>

Example

http://gitready.com/intermediate/2009/03/16/rolling-back-changes-with-revert.html

假设我们有这样一个 git 历史:

我们来一次 revert

1
2
3
4
$ git revert HEAD
Finished one revert.
[master]: created 1e689e2:
"Revert "Updated to Rails 2.3.2 and edge hoptoad_notifier""

revert 命令会自动帮你 commit, 并为你生成 commit 信息: Revert + 被回滚的 commit 的信息。
这里就是 “Revert “Updated to Rails 2.3.2 and edge hoptoad_notifier””

再来看下 revert 后的历史图:

可以看到 revert 的在最前面添加了一个 commit。

By default using this command will bring up your $EDITOR so you can modify the commit message of the revert.
Use this to explain why the changes are being backed out!
If for some reason you don’t want to edit the commit message, tacking on --no-edit will allow you do so.

另外如果你不想 commit 的话,还可以用 -n 参数

Another helpful option is the -n or –no-commit flag.
This will simply leave the reverted changes in your working directory and not automatically commit them.
If you need to edit files further to complete the revert or possibly revert more than one commit, try out this option.

接着,我们是试试看 revert 一个 merge 的 commit

1
2
$ git revert HEAD~1
fatal: Commit 137ea95 is a merge but no -m option was given.

它告诉你 commit 137ea95 是一个 merge, 需要你指定一个 -m 的option。

-m parent-number, –mainline parent-number
Usually you cannot revert a merge because you do not know which side of the merge should be considered the mainline.
This option specifies the parent number (starting from 1) of the mainline and allows revert to reverse the change relative to the specified parent.

意思是,你需要指定一个 parent number (从1开始),然后 revert 会将基于这个 parent number 的改变都回滚。

再来看下 merge commit 的信息

1
2
3
4
5
6
7
$ git log HEAD~1 -1
commit 137ea95c911633d3e908f6906e3adf6372cfb0ad
Merge: 5f576a9... 62db4af...
Author: Nick Quaranto <nick@quaran.to>
Date: Mon Mar 16 16:22:37 2009 -0400
Merging in rails-2.3 branch

可以看到 5f576a962db4af 被 merge 了。

所以

  1. git revert HEAD~1 -m 1 就会 revert 基于 5f576a9 所发生的变化
  2. git revert HEAD~1 -m 2 就会 revert 基于 62db4af 所发生的变化
1
2
3
4
5
6
7
8
9
10
11
12
13
$ git revert HEAD~1 --no-edit --mainline 2
Finished one revert.
[master]: created 526b346: "Revert "Merging in rails-2.3 branch""
$ git log -1
commit d64d3983845dfa18a5d935c7ac5a4855c125e474
Author: Nick Quaranto <nick@quaran.to>
Date: Mon Mar 16 19:24:45 2009 -0400
Revert "Merging in rails-2.3 branch"
This reverts commit 137ea95c911633d3e908f6906e3adf6372cfb0ad, reversing
changes made to 62db4af8c77852d2cc9c19efc6dfb97e0d0067f5.

很明确的告诉你, 这个 revert 提交了一个 commit: 137ea95c911633d3e908f6906e3adf6372cfb0ad,这个 commit 把 merge 操作对 62db4af8c77852d2cc9c19efc6dfb97e0d0067f5 发生的改变都回滚了。

通俗说法

  1. 普通的 revert: 比如桌上有一碗饭, 我吃完了,然后我又把这碗饭填满,像没吃一样, 填满的动作就是 revert。 看上去桌上的饭没有动过,但是事情其实发生了,就是历史没有被改变。
  2. merge 的 revert:桌上有一碗饭,A 加了一道菜, B 加了一碗汤, merge 之后就是有饭有菜有汤。 现在在有饭有菜有汤的情况下去掉汤, 就是 git revert "commit of merge" -m 菜
文章目录
  1. 1. 概念
  2. 2. Usage
  3. 3. Example
  4. 4. 通俗说法
|