在公共代码库中回滚到旧的Git提交记录

936

如何在 git 中回退到特定的提交版本?

有人给出的最佳答案是使用 git revert 多次操作,直到回到目标提交版本。

例如,如果我要回退到20个提交版本之前的某一版本,就需要执行20 次相应的操作。

是否有更简便的方法来实现这一目标呢?

由于这个仓库是公共的,因此无法使用 reset 命令。


1
git revert <commit> 不起作用? - miku
9
正如我在问题中所述,如果我想回到20个提交之前的某个状态,这并没有真正帮助我。 - David
8
这个问题在这里已经得到了很好的回答:https://dev59.com/im855IYBdhLWcg3w1oLa。 - user7610
6
“rolling back” 的意思不明确。这是否意味着您想暂时将工作副本切换到特定的版本?或者您确实想永久性地将存储库的历史记录恢复到某个特定版本?请说明清楚。 - user456814
2
你应该接受一个答案,并可能投票支持其他你喜欢的答案。 - Nabil Kadimi
相关:将Git仓库还原到以前的提交。请注意,该问题没有公共仓库的限制。 - user456814
13个回答

1368

试试这个:

git checkout [revision] .

在此命令中,[revision]是提交哈希值(例如:12345678901234567890123456789012345678ab)。别忘了在结尾处添加.,这非常重要。这将应用更改到整个树上。您应该在git项目根目录下执行此命令。如果您在任何子目录中,则此命令仅更改当前目录中的文件。然后进行提交即可。

您可以通过执行以下操作撤销此更改:

git reset --hard 

这将删除工作目录和暂存区的所有修改。


9
这句话结尾的句点指向你当前所在的目录,而不一定是整个git项目,对吗?如果你想将更改应用于整个项目,而不是当前目录,那么你会使用':/',就像在不在git项目根目录下一样。 - MSpreij
14
注意:如果你在此之后添加了新文件到你的项目中,这些文件不会被删除。因此在构建时(根据你使用的平台),你可能仍会遇到错误。删除新文件后就可以顺利进行了。 - TheWestIsThe...
7
请在 Git 项目根目录下执行此命令。如果您当前处于任何子目录中,则该命令仅更改当前目录中的文件。原意不变,语言通俗易懂。 - volatilevar
4
该死,我忘了加上“.”号,这会对我的代码库造成什么影响? - Owl
3
git checkout [revision] . 对我来说不起作用,没有任何反应。 - coder.chenzhi
显示剩余9条评论

238

要回滚到特定的提交:

git reset --hard commit_sha

要回滚10个提交:

git reset --hard HEAD~10

如果您不想重写历史记录,可以像下面这篇文章中所示使用“git revert”。

如何将Git仓库还原到以前的提交?


5
这种方法与"git checkout [revision] ."唯一的区别在于后者会保留历史版本。 - deeshank
63
这个答案是错误的,因为 OP 明确指出“我不能使用重置,因为这个仓库是公共的”。 - Yarin
5
如果代码仓库是公开的,我认为在不使用强制推送(git push -f)的情况下无法回滚公共仓库中的提交,因为这将影响在回滚之前拉取更改的其他人。因此,在公共仓库的本地沙盒中也可以使用 reset。 - Naga Kiran
4
很棒,这样可以避免游离状态的 HEAD!正是我正在寻找的。 - cyber-monk
3
@Yarin的回答很好,OP的前提条件是错误的,他可以在公共仓库上使用reset命令。对于我的“死灵评论”,抱歉;) - 9ilsdx 9rvj 0lo
显示剩余3条评论

99

嗯,我猜问题是什么意思,“回退”是什么意思?如果您无法“重置”因为它是公共的,并且您想保留提交历史记录,您是否意味着您只想让您的工作副本反映特定的提交?请使用git checkout和提交哈希。

编辑:正如评论中指出的那样,如果不指定分支使用git checkout,将使您处于“无分支”状态。使用git checkout <commit> -b <branchname>来检出到一个分支,或者使用git checkout <commit> .来检出到当前分支。


3
这不会让你陷入奇怪的“当前未在任何分支上”的状态吗?你如何提交更改以完成回滚? - Alex Reisner
好的,我只是建议使用 git checkout -- 他可以自由地检出到任何分支(当前或新的)。我会更新我的答案,以便不会有歧义。 - Ben
3
我尝试过这样做,但我认为这不是正确的方法,因为它会留下停滞不前的文件。这不会删除那些没有在最后一次提交中的文件。 - David
3
如果您在工作目录中并且停留在主分支上,您需要使用git reset命令来删除那些文件,但是您说您不想这么做。尝试在一个单独的分支中执行此操作:使用命令git checkout <commit> -b <branchname>,这样您就不会在该分支中拥有停滞不前的文件。 - Ben
那绝对是一个解决方案。如果有人编写一个Bash脚本,可以接受并运行还原操作,直到达到所需的哈希值,那该怎么办呢? - David
2
使用 checkout 的问题在于它不会删除之前提交中添加的文件。 - user456814

44

原帖作者说:

有人能给我最好的答案是使用 git revert X 次,直到我达到所需的提交。

所以假设我想要恢复到一个早于 20 个提交的提交,我需要运行它 20 次。

有更简单的方法吗?

我不能使用 reset,因为这个仓库是公开的。

不必使用 git revert X 次。 git revert 可以接受提交范围作为参数,因此您只需要使用一次即可还原一系列提交。例如,如果您想要还原最近的 20 个提交:

git revert --no-edit HEAD~20..

HEAD~20..的提交范围代表HEAD~20..HEAD,意思是“从HEAD提交的第20个父提交开始,回滚所有在它之后到HEAD的提交”。

这将撤销最近的20个提交,前提是其中没有合并提交。如果有合并提交,则无法通过一个命令撤销所有提交,您需要逐个撤销它们。

git revert -m 1 <merge-commit>

请注意,我已经使用git版本1.9.0测试了使用范围进行git revert的情况。如果您使用的是旧版本的git,则使用范围进行git revert可能会起作用,也可能不起作用。

在这种情况下,git revert优于git checkout

请注意,与this answer that says to use git checkout不同,git revert实际上会删除在您要还原的任何提交中添加的任何文件,这使得这是还原一系列修订的正确方法。

文档


1
注意:这将创建一个新的提交,撤销更改。非常适合 OP 的问题。但请确保这是您想要的。(上面链接的 git-revert 文档中的示例非常好。)如果您希望调查之前的提交(即在选择要还原到哪个提交之前),请使用其他答案中提到的 checkout 选项,记住其他人对已删除文件的评论。 - SherylHohman
1
@SherylHohman 回滚到以前的提交并不会创建一个新的提交。我无法想象你在这里的意思是什么。 - user146043

39

步骤1:获取提交列表:

git log

您会得到像这个例子中的列表:

[Comp:Folder User$ git log
commit 54b11d42e12dc6e9f070a8b5095a4492216d5320
Author: author <author@gmail.com>
Date:   Fri Jul 8 23:42:22 2016 +0300

This is last commit message

commit fd6cb176297acca4dbc69d15d6b7f78a2463482f
Author: author <author@gmail.com>
Date:   Fri Jun 24 20:20:24 2016 +0300

This is previous commit message

commit ab0de062136da650ffc27cfb57febac8efb84b8d
Author: author <author@gmail.com>
Date:   Thu Jun 23 00:41:55 2016 +0300

This is previous previous commit message
...

步骤 2:复制所需的提交哈希值,并将其粘贴以进行检出:

git checkout fd6cb176297acca4dbc69d15d6b7f78a2463482f

就这些了。


这只影响你本地,对吧?我需要找到错误发生的位置,打算使用这种方法不断获取不同的提交,直到错误消失。但我只想更改我的本地副本,而不是远程副本。 - Bob Horn

14

想要使用分离 HEAD 模式吗?

如果你希望回滚到某个特定的提交并使用分离 HEAD 模式(这意味着你不会弄乱任何东西),那么可以使用以下命令:

(将 X 替换为您希望回滚的提交数量)

git checkout HEAD~X

回退到上一个提交:

git checkout HEAD~1

11
git read-tree -um @ $commit_to_revert_to

会去做。 这是“git checkout”,但不会更新HEAD。

您可以使用

git checkout $commit_to_revert_to
git reset --soft @{1}

如果您更喜欢将方便的命令串联在一起。

这些命令使您的工作目录和索引处于所需状态,您只需使用git commit即可完成。


这是唯一直截了当的方法,非常有效!我从头检出,运行了这个命令,它成功地删除了我们引入的添加文件并还原了所有更改。太棒了。 - kamranicus

3

假设你在一个项目上工作,一天后发现仍然有一个功能出现错误。但你不知道哪个更改导致了这个错误。所以你必须找回之前可用的提交。要还原到特定的提交:

git checkout 8a0fe5191b7dfc6a81833bfb61220d7204e6b0a9 .

好的,这个提交对你有效。不再出现错误。你找到了问题点。现在可以回到最新的提交:

git checkout 792d9294f652d753514dc2033a04d742decb82a5 .

在引起错误之前查看特定文件(在我的情况下,我使用示例Gemfile.lock):

git checkout 8a0fe5191b7dfc6a81833bfb61220d7204e6b0a9 -- /projects/myproject/Gemfile.lock

这是一种处理你在提交中创建的错误,但直到后来才意识到这些错误的方法。


3

您可以在GitHub/BitBucket/Gitlab的提交部分找到与每个提交相关的提交ID。

非常简单,假设您的提交ID是5889575,如果想要返回到代码的这一部分,则只需要输入:

git checkout 5889575 .

这将带您到代码的那个时间点。


2

我不确定发生了什么变化,但是我无法在不使用--detach选项的情况下检出特定的提交。 对我有效的完整命令是:git checkout --detach [提交哈希]

要从分离状态返回,我必须检出我的本地分支:git checkout master


检出master分支解决了保持游离状态的问题,而执行git reset --hard或者git checkout -- .虽然起到了作用但仍旧保持着游离状态。 - DarkCygnus

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