将本地和远程git仓库回滚1次提交

268

我已经阅读了关于这个话题的类似帖子,但始终无法弄清楚如何正确地处理。

我检查了大约1000个文件,它们不是我想要的,我不想一个一个地从仓库中删除它们。

  • 我有一个远程的 master 分支。
  • 我有本地的 master 分支。

它们都在相同的版本上。

我想要将我的远程版本回滚1个提交。

假设我的master历史记录为A--B--C--D--E
我想将本地回滚到D
然后将其推送到远程,以便我的当前哈希值在远程和本地均为D。

我在处理此问题时遇到了一些问题。
我正在使用Git Tower,但使用命令行也很熟悉。 有什么帮助吗?

更新: 下面有很好的评论。使用重置似乎部分被反对,特别是如果仓库与其他用户共享。 没有使用硬重置的情况下撤消先前提交的更改的最佳方式是什么? 有什么方法吗?


我已经更新了我的答案,以“不使用硬重置撤消上一个提交的更改”。 - VonC
3
使用 git revert 进行撤销操作,无需进行硬重置并且不会影响其他用户。 - user562374
1
回滚远程操作是不被鼓励的,但如果您确实需要这样做,请自行操作。有很多方法可以实现这一点,但在服务器端的结果将是相同的。 - FelipeC
15个回答

431

如果还没有人拉取你的远程仓库,你可以更改你的分支HEAD并强制推送到该远程仓库:

git reset --hard HEAD^ 
git push -f 

(或者,如果您可以直接访问远程存储库,则可以更改其HEAD引用,即使它是裸仓库
请注意,如下方评论外星科技所述,在Windows(CMD会话)中,您需要使用^^
git reset --hard HEAD^^
git push -f 

正如Jon Schneider评论中指出的那样:

如果带有"HEAD^"的命令导致error no matches found: HEAD^错误,请参见"git show HEAD^ doesn't seem to be working. Is this normal?"。

自2011年以来更新:
使用git push --force-with-lease我在这里介绍,Git 1.8.5于2013年推出)更加安全。

请参见Schwern答案进行说明。


如果有人已经拉取了仓库,我该怎么办?

那么我建议使用一种不重写历史记录的方法:

  • git revert 本地撤销你的最后一次提交(创建一个新提交以撤销上一次提交所做的更改)
  • 推送由git revert生成的“撤销”。

1
@gwho 创建一个分支吗?不,它移动了分支的 HEAD,但你仍然在同一个分支中。然而,由于推送不再是快进式的,所以是的,你需要强制推送。 - VonC
1
有没有办法知道是否有人拉取了代码库? - Lv99Zubat
4
在Windows中,^字符用于进行代码行延续和转义字符,使得以下命令可以正常执行: git reset --hard HEAD^^ - Alien Technology
1
@AlienTechnology 在Windows 10上使用PowerShell,我只需要输入reset --hard HEAD^而不是reset --hard HEAD^^来重置最后一次提交。 - Puka
1
@JonSchneider 谢谢,好观点。我已将您的评论包含在答案中以增加可见性。 - VonC
显示剩余7条评论

79

将本地分支回退一个版本(HEAD^ 表示回退一个版本):

git reset --hard HEAD^

将更改推送到远程仓库:

git push --force

如果不强制推送的话,git会认为你比origin落后一个提交,什么都不会改变,所以你必须进行强制推送。

使用--force选项告诉git无视远端有任何进展,覆盖远端仓库中的HEAD


很好的回答。我读到过使用重置似乎在与其他用户共享存储库时部分不被鼓励。有没有更干净的方法来撤消之前提交的所有更改? - Jamis Charles
小心!将您未提交的更改藏起来,否则它们将会丢失。 - Nosov Pavel
很酷。那么,这是否意味着当我们执行 git push origin master 时,Git 能够在远程创建一个新的提交,因为本地分支至少领先于一次提交?此外,后者必须实质性地不同于远程仓库指向的 head 吗? - MadPhysicist
简单而有效的答案 - undefined

21

如果你想撤销上一次提交,请听:

步骤 1:

检查你本地的带有信息的提交记录

$ git log

步骤2:

从本地分支(或主分支)中删除最后一次提交,但不重置更改。

$ git reset HEAD^

或者,如果您不想要最后提交的文件并更新侦听器

$ git reset HEAD^ --hard

第三步:

我们可以更新文件和代码,并再次使用强制推送,它将删除以前的提交。它将保留新的提交。

$ git push origin branch -f

就是这样!


2
这不是“还原”提交,而是替换提交。请不要误用传统术语,以免让我们这些 Git 新手感到困惑。 - Suncat2000

11

通过输入以下命令,您可以查看 git 提交历史 -

$ git log

假设您在特定分支上的历史记录如下 - commit_A、commit_B、commit_C、commit_D。其中,commit_D 是最后一次提交,也是 HEAD 所在位置。现在,要从本地和远程中删除最后一次提交,您需要执行以下操作:

步骤 1:通过以下命令在本地删除最后一次提交 -

$ git reset --hard HEAD~

这将更改您的提交头(HEAD)到 commit_C。

步骤 2:将您的更改推送到新的 HEAD 提交到远程

$ git push origin +HEAD

此命令将从远程删除最后一次提交。

注:此命令已在 Mac OSX 上进行测试,并应该适用于其他操作系统(不保证其他操作系统能正常使用)


11

这是一个更安全的更新版程序。

git reset --hard HEAD^ 
git push --force-with-lease

git push -f 会无差别地用你的提交覆盖远程仓库。如果其他人已经推送了更改,那么这些更改将会丢失。git push --force-with-lease 只有在仓库状态符合你的预期时才会推送你的重置。如果其他人已经推送了更改,则你的推送将失败。

请参阅--force 被认为是有害的;了解 git 的 --force-with-lease

我建议将其别名为 repush = push --force-with-lease

如果有人已经拉取了仓库怎么办?那我该怎么做呢?

告诉他们执行 git pull --rebase=merges。它不像 git fetch origingit merge origin/master 那样,它会执行 git fetch origingit rebase -r origin/master。这将把他们本地对 master 所作的任何更改都重写到新的重置后的 origin/master 上面。-r 将保留他们可能进行的任何合并。

我建议将其设置为拉取时的默认行为。这是安全的,可以处理其他人的重置,并减少不必要的合并。

[pull]
        rebase = merges

我以为我昨天已经做了这个(问题):https://stackoverflow.com/posts/4647362/revisions - VonC

4

对于 Windows 机器,请使用以下命令:

git reset HEAD~1  #Remove Commit Locally

4

简单回答关于revert和reset的问题:

有许多方法可以做到这一点。根据您的需求从以下内容中选择任何一项。

1. 通过REVERT撤销提交:

如果您想要撤销您最后一次提交的所有更改,这意味着如果您向文件中添加了一些内容,那么在撤销完成后这些内容将被删除。如果您从文件中删除了某些内容,则还原过程会添加这些文件。

您可以撤销最后一次提交。例如:

1.git revert HEAD^
2.git push origin <Branch-Name>

或者您可以使用特定提交的哈希值来还原到任何以前的提交。例如:

1. git revert <HASH>
2.git push origin  <Branch-Name>

或者,如果提交是合并提交,您可以尝试以下方法:

1.git revert -m 1 <HASH> (-m 1 refers to the first parent of two merged branches)
2.git push origin  <Branch-Name>

2. 通过重置之前的HEAD指针

如果您想要指向任何以前的提交记录,只需使用reset操作;它将把您的本地环境重置到以前的提交记录。您可以将HEAD指针重置为先前的提交记录,或将其重置为以前的任何提交记录。

将HEAD指针重置到最后一个提交记录。

1.git reset HEAD^
2.git push -f origin <Branch-name>

回滚到之前的任意一次提交:

1.git reset <HASH>
2.git push -f origin <Branch-name>

REVERT和RESET之间的权衡:

  1. 为什么你会选择revert操作而不是reset操作?如果你已经将提交链推送到远程存储库(其他人可能已经拉取了你的代码并开始使用它),则revert是一种更好的方式来取消其对他们的更改。这是因为Git工作流适用于在分支末尾选择更多的提交,但如果一组提交在重置分支指针后不再在提交链中可见,则可能会带来挑战。

  2. 而重置分支可能会破坏您迄今为止所做的工作。因为当您重置提交时,GIT将删除此提交之后完成的所有提交。一个愚蠢的错误可能会毁掉你所有的辛苦工作,并且不保留任何你正在重置的历史记录。另一方面,在这种情况下revert一个提交是更好的选择。当您revert提交时,GIT将创建一个完全相反的更改与您想要revert的提交相对应,并指向该分支的末端。 因此,它不会在我们的愚蠢错误上搞乱任何东西。


3
你也可以这样做:
git reset --hard <commit-hash>
git push -f origin master

并且需要让所有拥有最新错误提交的其他人进行重置:
git reset --hard origin/master

1
我通过以下命令解决了和你类似的问题:

git reset --hard HEAD^
git push -f <remote> <local branch>:<remote branch> 

0
如果您只想从远程存储库中删除最后一次提交,而不会干扰本地存储库,那么可以使用以下一行命令:
git push origin +origin/master~:master

这使用以下语法:

git push <remote> <refspec>

在这里,<remote>origin,而 <refspec> 具有以下结构:
+origin/master~:master

详细信息可以在git-push(1)中找到。前面的+表示“强制推送此引用”,而另一部分表示“从origin/master~master(来自远程origin)”。很容易知道origin/master~origin/master之前的最后一次提交,对吧?


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