题 如何撤消Git中最近的提交?


我不小心提交了错误的文件 混帐,但我还没有将提交推送到服务器。

如何从本地存储库中撤消这些提交?


17823
2017-07-28 22:22


起源


警告:如果您尚未将提交推送到远程,则应该只执行此操作,否则您将搞乱已经从远程提取提交的其他人的历史记录! - thSoft
这里的 一个非常明确和彻底的帖子 关于在Git中撤消事物,直接来自Github。 - Nobita
有关Git提交撤消本地,公共和Git分支,请参阅本指南 如何撤消Git Commits像pro - Luzan Baral
在您发布新答案之前,请考虑此问题已有65个以上的答案。确保您的答案有助于现有答案中的答案。 - Sazzad Hissain Khan
你知道git需要什么吗? git undo, 而已。然后声誉git用于处理我们凡人的错误消失。通过在执行任何操作之前在git堆栈上按下当前状态来实现 git 命令。它会影响性能,因此最好添加一个配置标志,以确定是否启用它。 - Yimin Rong


答案:


撤消提交和重做

$ git commit -m "Something terribly misguided"             # (1)
$ git reset HEAD~                                          # (2)
<< edit files as necessary >>                              # (3)
$ git add ...                                              # (4)
$ git commit -c ORIG_HEAD                                  # (5)
  1. 这是您要撤消的内容
  2. 这会使您的工作树(磁盘上的文件状态)保持不变但撤消提交并保留您未提交的更改(因此它们将显示为“未提交的更改” git status,你需要在提交之前再次添加它们。如果你 只要 想要  对上一次提交的更多更改,或更改提交消息1,你可以使用 git reset --soft HEAD~ 相反,这就像 git reset HEAD~ (哪里 HEAD~ 是相同的 HEAD~1)但是现有的更改会暂停。
  3. 对工作树文件进行更正。
  4. git add 您想要包含在新提交中的任何内容。
  5. 提交更改,重用旧的提交消息。 reset 将旧头复制到 .git/ORIG_HEAD; commit 同 -c ORIG_HEAD 将打开一个编辑器,该编辑器最初包含旧提交的日志消息,并允许您编辑它。如果您不需要编辑邮件,则可以使用 -C 选项。

但请注意,如果您已为索引添加了任何新更改,请使用 commit --amend 将它们添加到您之前的提交。

如果代码已经推送到您的服务器并且您有权覆盖历史记录(rebase),那么:

git push origin master --force

你也可以看看这个答案:

如何将HEAD移回以前的位置? (独立头)

以上答案将告诉你 git reflog 用于找出您希望恢复的SHA-1是什么。一旦找到要撤消的点,就可以使用上面解释的命令序列。


1 但请注意,如果您在自己的错误中犯了错误,则无需重置为先前的提交 提交消息。更容易的选择是 git reset (以便更新你所做的任何改变)然后 git commit --amend,这将打开预先填充了最后一次提交消息的默认提交消息编辑器。


19285
2018-06-16 17:27



如果提交是错误的分支,你可以 git checkout theRightBranch 所有变化阶段。正如我必须做的那样。 - Frank Shearar
如果您在DOS中工作,而不是 git reset --soft HEAD^ 你需要使用 git reset --soft HEAD~1。 ^是DOS中的延续字符,因此无法正常工作。也, --soft 是默认值,因此如果您愿意,可以省略它 git reset HEAD~1。 - Ryan Lundy
另外,在zsh中你必须引用^,所以 git reset --soft 'HEAD^'......至少我做到了 - jberryman
(纠正我上面所写的内容; --mixed 是默认值。 --mixed 意味着保留已更改的文件,但不将它们保留在索引中。 --soft 将保留更改的文件并将它们保留在索引中,就像它们在更改的提交之前一样。对困惑感到抱歉。) - Ryan Lundy
zsh用户可能会得到: zsh: no matches found: HEAD^  - 你需要逃避^即 git reset --soft HEAD\^ - tnajdek


如果你不知道如何工作,撤销提交有点可怕。但是如果你理解的话,这实际上非常容易。

假设你有这个,其中C是你的HEAD,(F)是你文件的状态。

   (F)
A-B-C
    ↑
  master

你想要 nuke提交C并且永远不会再看到它。你做这个:

git reset --hard HEAD~1

结果是:

 (F)
A-B
  ↑
master

现在B是HEAD。因为你用过 --hard,您的文件将重置为它们在提交B的状态。

啊,但是假设提交C不是灾难,但只是有点偏。你想要 撤消提交但保留更改 在进行更好的提交之前进行一些编辑。从这里开始,用C作为你的HEAD:

   (F)
A-B-C
    ↑
  master

你可以这样做,不用了 --hard

git reset HEAD~1

在这种情况下,结果是:

   (F)
A-B-C
  ↑
master

在这两种情况下,HEAD只是指向最新提交的指针。当你这样做的时候 git reset HEAD~1,你告诉Git将HEAD指针移回一次提交。但是(除非你使用 --hard你按原样保留文件。所以现在 git status 显示您已检入C的更改。您没有丢失任何东西!

对于最轻的触摸,你甚至可以 撤消您的提交,但保留您的文件和您的 指数

git reset --soft HEAD~1

这不仅会使您的文件单独存在,甚至会使您的文件丢失 指数 单独。当你这样做 git status,你会看到索引中的文件和以前一样。事实上,在这个命令之后,你可以做到 git commit 而且你将重做你刚刚做过的同样的提交。

还有一件事: 假设你销毁了一个提交 如在第一个例子中, 但后来发现你需要它?运气好,对吗?

不,那是 仍然 一种回归的方法。类型 git reflog 你会看到你已经移动过的(部分)提交sha的列表。找到你销毁的提交,并执行以下操作:

git checkout -b someNewBranchName shaYouDestroyed

你现在已经复活了这个提交。提交实际上并没有在Git中被摧毁大约90天,所以你通常可以回去拯救一个你并不想要摆脱的东西。


9734
2018-05-29 18:16



@dma_k,是的。或者你可以做到 git reset --hard HEAD^^ 一旦。我使用波浪号(〜)表示法,因为插入符号(^)符号在DOS中不起作用。 - Ryan Lundy
另一个不错的提示:您可以将分支重新附加到您从中删除它的提交 git branch -f <branch> <commit-id>。节省必须重新创建提交! - naught101
对于一个git初学者来说,最后两个选项(--soft和它上面的选项)之间的区别并不明显。提到索引没有帮助,我们真的不知道这意味着什么。 @ nessur在soft和Ctrl-Z之间的连接确实有帮助!但我仍然不太明白这两个选项之间的区别。 - Stomp
被告知“为什么”有效的方式要好得多,而不仅仅是被告知答案。感谢这个描述 - 它帮助'得到'git。 - Chris Nash
缺少一个关键点:如果所述提交先前被“推送”到远程,任何“撤销”操作,无论多么简单,都会给在本地副本中提交此提交的其他用户带来巨大的痛苦和痛苦,当他们将来做'git pull'时。因此,如果提交已被“推送”,请执行以下操作:git revert <bad-commit-sha1-id> git push origin: - FractalSpace


我花了一段时间才弄明白,所以也许这会帮助别人......

根据您是否已将提交公开(推送到远程存储库),有两种方法可以“撤消”上次提交:

如何撤消本地提交

假设我在本地提交,但现在想删除该提交。

git log
    commit 101: bad commit    # latest commit, this would be called 'HEAD'
    commit 100: good commit   # second to last commit, this is the one we want

要将所有内容恢复到上次提交之前的状态,我们需要 reset 之前的提交 HEAD

git reset --soft HEAD^     # use --soft if you want to keep your changes
git reset --hard HEAD^     # use --hard if you don't care about keeping the changes you made

现在 git log 将显示我们的上一次提交已被删除。

如何撤消公共提交

如果您已将提交公开,则需要创建一个新的提交,它将“还原”您在先前提交(当前HEAD)中所做的更改。

git revert HEAD

您的更改现在将被还原并准备好您提交:

git commit -m 'restoring the file I removed by accident'
git log
    commit 102: restoring the file I removed by accident
    commit 101: removing a file we don't need
    commit 100: adding a file that we need

有关详细信息,请查看 Git Basics - 撤消事物


1751
2018-05-29 18:13



我发现这个答案最清楚。 git revert HEAD^ 不是以前的,是以前的。我做了: git revert HEAD 然后再推,它工作:) - nacho4d
@riezebosch:你的警告是在错误的地方。这个答案不会搞砸事情,因为它正确地创建了一个新的提交102:“恢复我在意外删除的文件” - rubo77
这是最好的答案,因为它不会混淆你的git历史 - Lukas


添加/删除文件以获得您想要的方式:

git rm classdir
git add sourcedir

然后修改提交:

git commit --amend

之前的错误提交将被编辑以反映新的索引状态 - 换句话说,它就像你从来没有犯过错误。

请注意,只有在尚未推送的情况下才应执行此操作。如果你已推,那么你只需要正常提交修复。


1625
2017-07-31 09:39



当我这样做时,这是否有效 git commit --amend 我真正打算做的是一个 git commit? - dbm
@dbm,如果你不小心修改,请使用 git reset --soft <oldref>,其中oldref是修改前的提交ID。您可以使用 git reflog 识别旧的提交ID。这将取消修改的效果,但保留更改阶段。然后就做 git commit 提交作为常规提交。 - bdonlan
@ Dennis,git commit --amend将当前树(即分阶段更改)转换为提交,覆盖当前HEAD。在那之后,它们不再被认为是阶段性的,因为它们是提交的一部分(即,git diff --cached是空白的),但它们不会被“删除”或“丢失”。 - bdonlan


git rm yourfiles/*.class
git commit -a -m "deleted all class files in folder 'yourfiles'"

要么

git reset --hard HEAD~1

警告:以上命令将永久删除对该修改 .java 您要提交的文件(以及任何其他文件)。

hard reset 至 HEAD-1 在您错误提交之前,会将您的工作副本设置为提交状态。


878
2018-05-25 16:04



“--hard”将删除他想要提交的工作目录中的修改后的.java文件。 - Esko Luontola
您可以“git stash save”工作副本更改,执行硬重置,然后“git stash pop”将其恢复,但我认为软重置会更简单。 - Asad R.
git commit -a -m "" 要么 git commit -am "" 自然! :] - trejder
隐藏的另一个“捷径”用途;如果你想取消所有内容(撤消git add),只需 git stash, 然后 git stash pop - seanriordan08


要更改上次提交

替换索引中的文件:

git rm --cached *.class
git add *.java

然后,如果它是一个私人分支, 修改 提交:

git commit --amend

或者,如果它是共享分支,则进行新的提交:

git commit -m 'Replace .class files with .java files'


更改先前的提交,使用真棒 交互式rebase


ProTip:添加 *.class 到了 gitignore 再次阻止这种情况发生。


要还原提交

如果您需要更改上次提交,则修改提交是理想的解决方案,但更通用的解决方案是 reset

您可以将git重置为任何提交:

git reset @~N

哪里 N 是之前提交的数量 HEAD,和 @~ 重置为先前的提交。

因此,您可以使用以下命令而不是修改提交:

git reset @~
git add *.java
git commit -m "Add .java files"

查看 git help reset,特别是关于的部分 --soft  --mixed 和 --hard,为了更好地理解这一点。

引用日志

如果你陷入困境,你总是可以使用reflog来查找丢弃的提交:

$ git reset @~
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~
2c52489 HEAD@{1}: commit: added some .class files
$ git reset 2c52489
... and you're back where you started



679
2018-01-31 07:06



对于那些将来阅读的人 - 请注意 git revert 是一个单独的命令 - 基本上'重置'单个commimt。 - BKSpurgeon


使用 git revert commit-id

要获取提交ID,只需使用 git log


549
2017-12-13 10:18



如果你犯了错误的分支:一旦恢复,切换到正确的分支并挑选提交。 - Kris
这意味着什么,樱桃选择提交?在我的情况下,当我编辑文件时,我在错误的分支上。我承诺,然后意识到我在错误的分支。使用“git reset --soft HEAD~1”让我回到提交之前,但是现在如果我签出了正确的分支,我如何撤消对错误分支中的文件的更改,而是使它们(在相同的命名中)文件)在正确的分支? - astronomerdave
我只是利用了 git revert commit-id 像魅力一样工作。当然,您需要推动您的更改。 - Casey Robinson
我相信那会是 git cherry-pick <<erroneous-commit-sha>> @astronomerdave。从,差不多2年 - 晚到党。 - Tom Howard


如果您计划完全撤消本地提交,无论您在提交时做了什么更改,如果您对此没有任何担心,只需执行以下命令即可。

git reset --hard HEAD^1

(此命令将忽略您的整个提交,您的更改将完全从本地工作树中丢失)。如果要撤消提交,但希望在暂存区域中进行更改(在提交之前就像之后一样) git add)然后执行以下命令。

git reset --soft HEAD^1

现在,您提交的文件将进入暂存区域。假设您要取消暂存文件,因为您需要编辑一些错误的内容,请执行以下命令

git reset HEAD

现在提交的文件从暂存区域进入未分区区域。现在文件已准备好进行编辑,因此无论您如何更改,都需要进行编辑并添加它并进行新的/新的提交。

更多


441
2018-04-06 13:58



@SMR,在你的例子中,所有都只指向当前的HEAD。 HEAD ^ = HEAD ^ 1。和HEAD ^ 1 = HEAD~1一样。当您使用HEAD~2时,〜和^符号之间存在差异。如果你使用~2表示“第一个父母的第一个父母”或“祖父母”。 - Madhan Ayyasamy
清晰易懂,拯救我的夜晚! - Vladimir Ch
显然,我不小心贬低了这个答案,现在为时已经太迟了。道歉。 - Matt


如果你有 Git Extras 安装后,即可运行 git undo 撤消最新提交。 git undo 3 将撤消最后3次提交。


431
2017-10-25 03:41