如何使用 Git Revert

258

git revert 是如何使用的?

这可能听起来像是一个重复的问题,但当人们提出这个问题时,通常的回答是按照“在Git中通过SHA哈希值还原提交”中的方法使用 git reset

然后当有人问如何使用 git reset 时,人们会回答说你应该按照“Git - 如何回滚”中的方法使用 git revert

然后八个不同的人都会出现,并且每个人都有自己独特的方式来解决问题,所有这一切对你来说都太高深了。

所以让我们试着简化并编写一个关于 git revert 的白痴指南。

场景:你已经向主分支提交了两次,并且它们很糟糕。 你已经推送并且其他人也有了你糟糕的更改。

你想撤销它。 如果有些巫师或软件包管理器在各处更改了大量的东西,这不是你可以手动撤销的东西-您只想把一切都恢复到以前的状态。

这就是源代码控制所关注的。我相信它很容易。

好的,你将使用 git revert,但是如何使用呢?

运行 git revert 后,是否还需要进行其他操作? 是否需要提交 revert 所做的更改,或者 revert 是否直接提交到仓库中?

显然,你需要再次推送,并且可能要向团队通报你的失误。


1
我的IDE刚刚询问是否要使用**--edit选项。使用此选项,git revert将允许您在提交还原之前编辑提交信息。如果您从终端运行命令,则这是默认设置。--no-edit选项将使git revert不启动提交信息编辑器**。详见文档 - cachius
7个回答

249

git revert会创建一个新的提交

git revert只是创建了一个与现有提交相反的新提交。

它保持文件的状态与还原该提交之前一样。例如,考虑以下简单示例:

$ cd /tmp/example
$ git init
Initialized empty Git repository in /tmp/example/.git/
$ echo "Initial text" > README.md
$ git add README.md
$ git commit -m "initial commit"
[master (root-commit) 3f7522e] initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
$ echo "bad update" > README.md 
$ git commit -am "bad update"
[master a1b9870] bad update
 1 file changed, 1 insertion(+), 1 deletion(-)

在这个示例中,提交历史有两次提交,最后一次是一个错误。使用 git revert:

$ git revert HEAD
[master 1db4eeb] Revert "bad update"
 1 file changed, 1 insertion(+), 1 deletion(-)

日志中将有3个提交:

$ git log --oneline
1db4eeb Revert "bad update"
a1b9870 bad update
3f7522e initial commit

因此,存在一致的历史记录表明发生了什么,但文件好像从未发生过错误更新:

cat README.md 
Initial text

无论要回滚的提交在历史记录中的何处(在上面的示例中,回滚最后一次提交 - 任何提交都可以被回滚)。

结束问题

之后还需要做其他事情吗?

git revert只是另一个提交,因此例如将更改推送到远程以便其他用户可以拉取/获取/合并更改,完成后就可以了。

您是否需要提交还原所做的更改,或者还原是否直接提交到存储库?

git revert是一个提交 - 假设撤消单个提交是您想要执行的操作,则没有额外步骤。

显然,您需要再次推送,并可能向团队宣布。

的确 - 如果远程处于不稳定状态 - 向其余团队传达他们需要拉动以获取修复(回滚提交)的信息是正确的做法 :)。


为了确认第一条声明以及任何想知道它如何工作的人,您可以还原还原操作,其中自还原操作以来有几个新提交。因此,还原确实只是还原提交的相反操作。当然,您可能会遇到冲突...但那是另一回事。 - GG2
1
我总是觉得最好避免提交,仅先检查更改,然后使用 git revert -n <commitToRevert>git revert --no-commit <commitToRevert> - Eklavyaa
10
只是想说,在 Stack Overflow 多年后,我认为这可能是我遇到过的最好的答案之一。很棒的示例和解释。谢谢。 - user3344977
我来到这里是为了获取更多信息,例如这个链接中的TLDR https://raw.githubusercontent.com/git/git/master/Documentation/howto/revert-a-faulty-merge.txt - wviana
3
如果你找到的信息不足,请写一个答案。请注意,Stack Overflow不能替代官方文档(你似乎正在链接它,并且覆盖的范围比这个问题要广泛得多)。 - AD7six
所以我尝试了一些实验,当你回滚时,它会将你带回到HEAD(最新提交)之前的上一个提交,我的实验结果是这样的。谢谢! - Ice Bear

81

使用 Git revert 的方式如下:

git revert <插入有问题的提交哈希值>

git revert 会创建一个新的提交,撤销之前的更改。而 git reset 则会擦除您的 Git 历史记录,而不是创建新的提交。

其余步骤与其他提交相同。


1
“撤销提交”和“撤销到某个提交”的区别微妙得足以让我苦苦思索多年。您的解释立刻为我解决了这个问题。谢谢! - claviska

70

这个问题很老了,但是撤销操作(revert)仍然会让人感到困惑(比如我)

作为一个初学者,在一些尝试和错误后(错误多于尝试),我得出了一个重要的观点:

  • git revert 需要你想要移除的提交记录的id,并将其保留在你的历史记录中。

  • git reset 需要你想要保留的提交记录,并将在此之后的任何记录从历史记录中删除。

也就是说,如果你使用revert来回滚第一个提交记录,你会发现自己处于一个空目录中,并且历史记录中还有一个附加的提交记录;而使用reset则会将你的目录还原到初始提交,并且你的历史记录会像最后的提交记录(们)从未存在过一样。

为了更清楚地说明,假设有这样一条提交记录日志:

# git log --oneline

cb76ee4 wrong
01b56c6 test
2e407ce first commit

使用git revert cb76ee4默认会将您的文件恢复到01b56c6,并将其作为一次进一步的提交添加到您的历史记录中:

8d4406b Revert "wrong"
cb76ee4 wrong
01b56c6 test
2e407ce first commit

git reset 01b56c6会将你的文件恢复到版本号为01b56c6的状态,并且会清除该版本之后的所有提交记录:

git reset 01b56c6会将你的文件回滚到指定的提交版本,同时这个操作也会将最近的提交从提交历史中删除,因此请谨慎使用。

01b56c6 test
2e407ce first commit

我知道这些是“基础知识”,但对我来说很困惑,通过在第一个ID(“第一次提交”)上运行revert,我希望找到我的初始文件,这需要一段时间才能理解,如果您需要将文件恢复为“第一次提交”,则需要使用下一个ID。


2
我也有这样的体验。虽然很令人困惑,但了解它非常重要。就在最近,我不得不帮助一位同事,并忘记了这一点。那有点尴尬。 - ExOfDe

29

resetrevert在同一谈话中经常被提起的原因是不同版本控制系统将它们用于表示不同的含义。

具体而言,那些习惯使用SubversionPerforce的人们,在想要放弃对文件所做的未提交更改时,通常会首先想到使用revert,但他们需要被告知实际上应该使用的是reset

同样地,在其他VCSes中与revert等价的命令通常被称为rollback或类似的名称,但是"rollback"也可以表示"我想要完全放弃最近的几次提交",这对于reset适用,但不适用于revert。因此,人们知道他们想要做什么,但不清楚应该使用哪个命令,这导致了很多混淆。

至于您关于revert的实际问题...

好的,你将使用git revert,但是如何操作?

git revert first-bad-commit^..last-bad-commit

注意,对于first-bad-commit,有一个“^”字符。这引用了first-bad-commit的父级,因为还原范围不包括起始提交。

运行git revert之后,您是否需要执行其他操作?您是否必须提交还原所做的更改,或者还原会直接提交到存储库中,或者怎么样?

默认情况下,git revert会提示您输入提交消息,然后提交结果。这可以被覆盖。我引用手册

--edit

使用此选项,git revert将允许您在提交还原之前编辑提交信息。如果您从终端运行命令,则此为默认选项。

--no-commit

通常,该命令会自动创建一些提交,其中提交日志消息说明哪些提交已被还原。此标志应用于撤销指定提交所需的更改到您的工作树和索引,但不会进行提交。此外,当使用此选项时,您的索引不必与HEAD提交匹配。还原是针对您的索引的初始状态完成的。

当连续还原多个提交的效果到您的索引时,这非常有用。

特别地,默认情况下,它为您要还原的每个提交创建一个新提交。您可以使用revert --no-commit来创建还原所有这些更改而不将这些更改作为单独的提交提交,然后在适当的时候进行提交。


1
我认为应该是 git revert parent-of-first-bad-commit..last-bad-commit - user1071847
1
@user1071847 是正确的。范围语法是错误的。我已经进行了编辑以修复它。 - itsafire

4

我运行了“git revert commit id”命令,撤销回去了几个提交,例如:

git revert b2cb7c248d416409f8eb42b561cbff91b0601712

然后我被提示提交回滚(就像运行'git commit'一样)。 我的默认终端程序是Vim,所以我运行了以下命令:

:wq 

最后,我使用以下代码将更改推送到仓库:

git push

3
下面的信息图表显示,git revert本质上是一个倒置的git cherry-pick,通过向前滚动来撤消东西;被还原的目标提交保留在历史记录中!
当您无法重写整个历史记录,但仍想完全撤消早期提交时,请使用git revert。与大多数Git命令一样,还原是在本地执行的,因此需要推送所得到的提交才能与团队共享。

Infographic showing how "git revert" is essentially an inversed "git cherry-pick", undoing stuff by rolling forward


1
git revert HEAD~x --no-edit

--no-edit跳过提交消息编辑器

x是一个数字。它表示你想要回退的步数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接