如何在Git中撤销最近的本地提交?

26051
我不小心提交了错误的文件到Git,但还没有将提交推送到服务器。
我该如何从本地仓库撤销这些提交?

684
你知道git需要什么?就是"git undo",这样一来,git对于我们这些凡人所犯下的错误的处理名声就消失了。实现的方法是在执行任何"git"命令之前将当前状态推送到git堆栈上。这会影响性能,所以最好增加一个配置标志来决定是否启用它。 - Yimin Rong
57
可以使用Git的“alias”功能来完成这个操作:https://git-scm.com/book/zh/v2/Git-基础-Git-别名 - Edric
134
针对VsCode用户,只需按下ctrl+shift+G,然后单击三个点,即“更多选项”,接着再点击“撤销上一次提交”。请注意,翻译过程中不会添加解释或其他任何额外信息。 - ashad
29
您要撤销的是什么?有很多不同的功能用例,其中“撤销”意味着完全不同的事情。我敢打赌,添加一个新的花哨的“魔法棒”只会更加混淆事情。 - Romain Valeri
50
不太相信,人们仍然会弄乱并撤销不应该撤销的事情。但更重要的是,git reflog 已经接近你所描述的内容,但它给用户更多的控制权来确定需要(撤销)做的事情。但是请注意,“撤销”在各个地方的工作方式不同,人们会期望这个功能实现许多不同的事情。撤销上一个提交?撤销上一个操作?如果最后一个操作是推送,如何撤销,(重置并推送)还是(撤销并推送)? - Romain Valeri
显示剩余10条评论
107个回答

65

我的情况是我将代码提交并推送到了错误的分支,因此我想要把所有修改都拿回来,这样我就可以将它们提交到一个新的正确的分支中。所以我执行了以下操作:

在你提交和推送的同一个分支上,如果你输入“git status”命令,你看不到任何新的内容,因为你已经提交和推送了。现在输入以下命令:

    git reset --soft HEAD~1

这将把所有更改(文件)放回到暂存区,现在要将它们放回工作目录(取消暂存),只需键入:

git reset FILE

“File”是您想要再次提交的文件。现在,此文件应该位于工作目录(未暂存)中,并带有您进行的所有更改。现在,您可以切换到任何您想要的分支并提交该分支中的更改。当然,您最初提交的分支仍然具有所有更改,但在我的情况下,这没问题。如果对您来说不行,您可以寻找在该分支中撤销该提交的方法。


64

撤销上一个提交:

git reset --soft HEAD^ or git reset --soft HEAD~

这将撤销最近的提交。

这里的--soft表示重置为暂存区。

HEAD~或HEAD^表示移动到HEAD之前的提交。

将最近的提交替换为新的提交:

git commit --amend -m "message"

它将用新的提交替换最后一次提交。


61
如果您正在使用 SourceTree,这将对您有所帮助。
在提交上右键单击,然后选择 "重置(当前分支)/主分支到此提交",最后选择 "软" 重置在这里输入图片描述

59

要撤销您的本地提交,您可以使用git reset <commit>。此外,该教程非常有帮助,以展示它的工作原理。

或者,您可以使用git revert <commit>:在想要添加另一个提交来回滚更改(但将其保留在项目历史记录中)时,应使用还原命令。


在还原合并提交时要特别小心,否则可能会丢失您的提交。请阅读Linus对此的说法:https://www.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty-merge.html - Eugen Konkov
请注意,对于 git reset <commit> 命令,请使用要重置到的上一个提交的提交 sha,而不是要取消暂存的提交。 - Rich G

57

假设你在本地提交了错误的内容并将其推送到远程仓库。你可以使用以下两个命令来撤消这个错误:

首先,我们需要通过回退到我们想要的提交来纠正我们的本地仓库:

git reset --hard <previous good commit id where you want the local repository  to go>

现在我们可以使用以下命令强制将此良好提交推送到远程存储库:

git push --force-with-lease

使用带有'with-lease'选项的force命令可以防止意外删除您不知道的新提交(即自上次拉取以来来自另一个源的提交)。


1
这对我来说是最好的解决方案,因为我已经将错误提交推送到了Github。 - AeroHil

52

每个人的评论都很复杂。

如果你想从你的分支中移除最后一次提交,最简单的方法是:

git reset HEAD~1

git reset --hard HEAD~1

现在,为了实际推送那个更改以消除你最后的提交,你需要执行以下操作:

git push --force

就这样了。这将删除你的最后一次提交。


6
请注意,使用 "--hard" 选项会完全丢弃最后一次提交所做的所有更改以及索引中的内容。 - CloudJR
是的,在我们只需要修复提交时,我们不应该使用“--hard”,而应该将其保留为默认的“--soft”,这样我们就可以在“git push -f”之前删除和添加内容。 - Maf

52

VISUAL STUDIO 用户(2015等)

如果你不能在 Visual Studio 中进行同步,因为你没有权限推送到类似“开发”这样的分支,那么无论我如何尝试,在 Visual Studio 中,回滚重置(硬重置或软重置)都不会起作用。

根据获得大量赞同票的答案:

在项目根目录的命令提示符中使用以下命令,清除任何将尝试被推送的内容:

git reset --hard HEAD~1

备份或压缩文件,以防止您不希望丢失任何工作等...


51

典型的Git工作流程

在之前的回答中提到了与Git相关的命令,我想与所有读者分享我的典型Git工作流程,这可能会有所帮助。下面是我如何使用Git:

  1. 第一次从远程服务器克隆

    git clone $project

  2. 从远程拉取(当我没有等待推送的本地提交时)

    git pull

  3. 将新的本地file1添加到$to_be_committed_list中(只需想象$to_be_committed_list表示staged区域即可)

    git add $file1

  4. $to_be_committed_list中删除错误添加的file2(假设像第3步一样添加了该文件,但我不想要它)

    git reset $file2

  5. 提交在$to_be_committed_list中的file1

    git commit -m "提交消息描述"

  6. 在推送之前将本地提交与远程存储库同步

    git pull --rebase

  7. 解决冲突时,先预设合并工具

    git mergetool #在这里解决合并问题,也可以手动合并

  8. 添加已解决冲突的文件,比如file1:

    git add $file1

  9. 继续上一个rebase命令

    git rebase --continue

  10. 推送准备好且已同步的本地最后一次提交

    git push origin head:refs/for/$branch #分支=master、dev等


如果我正在使用分支工作,那么我基本上有两个远程仓库:实际的仓库(例如incubator-mxnet)和我的分支仓库(ChaiBapchya/incubator-mxnet)。在这种情况下,我该如何解决从本地到我的分支仓库分支的合并冲突呢? - Chaitanya Bapat

48
在这些情况下,“reset”命令是您最好的朋友:
git reset --soft HEAD~1

重置会将当前HEAD分支回滚到指定的修订版本。在我们上面的例子中,我们想回到当前修订版本之前的那个版本 - 有效地撤消了我们最后一次提交。

请注意--soft标志:这可以确保未做的修订中的更改被保留。运行命令后,您将在工作副本中找到更改为未提交的本地修改。

如果您不想保留这些更改,只需使用--hard标志。请务必只在确定不再需要这些更改时才这样做。

git reset --hard HEAD~1

46
为了消除(最近提交的)最后一个提交、最后两个提交和最后 n 个提交中的所有更改:
git reset --hard HEAD~1
git reset --hard HEAD~2
...
git reset --hard HEAD~n

要删除特定提交后的所有内容:

git reset --hard <commit sha>

e.g.,

git reset --hard 0d12345

使用"硬重置"要小心:它将删除你仓库中的本地更改,并恢复到前面提到的上一个提交。只有在你确信你弄糟了你最后一次提交并想要回到之前的状态时,才应该运行此命令。

顺便说一下,在提交哈希中约7个字母就足够了,但对于大型项目,您可能需要多达12个字母才能确保其唯一性。您也可以使用整个提交SHA。

以上命令在GitHub for Windows中同样适用。


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