如何在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个回答

29
git reset --soft HEAD~1

重置将把当前的HEAD分支回退到指定的修订版本。

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

如果您不想保留这些更改,请使用--hard标志。请务必在确定不再需要这些更改时才执行此操作。

 git reset --hard HEAD~1

撤销多个提交

git reset --hard 0ad5a7a6

请记住,使用reset命令会撤销您回退到的提交之后的所有提交:

这里输入图片描述


27

这是一个网站:Oh shit, git!

这里有许多关于如何撤销 Git 操作的技巧。其中一些包括:

天啊,我需要修改上一个提交的信息!

git commit --amend
# follow prompts to change the commit message

糟糕,我不小心把一些本应该在全新分支上的内容提交到了主分支!

# Create a new branch from the current state of master
git branch some-new-branch-name
# Remove the commit from the master branch
git reset HEAD~ --hard
git checkout some-new-branch-name
# Your commit lives in this branch now :)

27

您可以从本地仓库撤销提交。请按照以下步骤进行操作。

在下面的图片中,我使用 Git 命令 git checkout -b test 检出了 'test' 分支作为本地分支,并检查了本地分支的状态(使用 Git 命令 git status),确认没有需要提交的内容。

Enter image description here

在下一张图片中,您可以看到我对 Filter1.txt 进行了一些更改,并将该文件添加到暂存区,然后使用一些消息提交了我的更改(使用 Git 命令 git commit -m "Doing commit to test revert back")。

"-m 是提交消息的缩写"

Enter image description here

在下一张图片中,您可以看到提交日志,了解您所做的每个提交(使用 Git 命令 git log)。

Enter image description here

因此,您可以在上面的图像中看到每个提交的提交 ID 和提交消息,现在无论您想要还原或撤消哪个提交,请复制该提交 ID 并使用下面的 Git 命令:git revert {"paste your commit id"}。例如:

git revert 9ca304ed12b991f8251496b4ea452857b34353e7

输入图像描述

我已经撤销了上一次提交。现在,如果您检查Git状态,您会看到修改过的文件,即Filter1.txt,尚未提交。

输入图像描述


27

撤销最后一次提交的最简单方法是

git reset HEAD^

这将使项目回到您提交之前的状态。


27

为了完整起见,我将提供一个之前的答案中被忽略的明显方法。

由于提交未推送,远程没有更改,因此:

  1. 删除本地存储库。
  2. 克隆远程存储库。

如果您的Git客户端消失不见了(看着你,egit),这有时是必要的。

别忘了重新提交上次推送以来的保存更改。


26
我发现了描述如何撤消已提交到代码库中的更改的这个网站。
一些命令:
git commit --amend        # Change last commit
git reset HEAD~1 --soft   # Undo last commit

26

参考:如何在 Git 中撤消上次提交?

如果您已经安装了 Git Extensions,则可以轻松地撤消/还原任何提交(可以从这里下载 Git Extensions)。

打开 Git 扩展,右键单击要还原的提交,然后选择“还原提交”。

Git扩展屏幕截图

将打开一个弹出窗口(请参见下面的截屏)

还原提交弹出窗口

如果想直接提交被还原的更改,请选择“自动创建提交”,如果想手动提交被还原的更改,请勿选择该框,并单击“还原此提交”按钮。


25
在回答问题之前,让我们先了解一下什么是HEAD

首先,什么是HEAD?

HEAD只是当前分支上最新提交的引用。在任何给定时间只能有一个HEAD(不包括git worktree)。 HEAD的内容存储在.git/HEAD中,其中包含当前提交的40个字节SHA-1值。

分离的 HEAD

如果你不在最新的提交上 - 意味着 HEAD 指向历史中的先前提交,这被称为分离的 HEAD

Enter image description here

在命令行中,它看起来是这样的 - SHA-1而不是分支名称,因为 HEAD 没有指向当前分支的末尾:

Enter image description here

Enter image description here


如何从分离的HEAD中恢复的几个选项:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits to go back

这将检出指向所需提交的新分支。
此命令将检出到给定的提交。
此时,您可以创建一个分支并从此点开始工作。

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

你可以始终使用 reflog
git reflog 将显示更新了 HEAD 的任何更改,检出所需的 reflog 条目将把 HEAD 设置回此提交。

每次修改 HEAD 都会在 reflog 中创建一个新条目

git reflog
git checkout HEAD@{...}

这将使你回到所需的提交。

Enter image description here


git reset --hard <commit_id>

将你的HEAD指针移回到所需的提交记录。

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.

注意:(自Git 2.7起)你也可以使用git rebase --no-autostash

enter image description here


git revert <sha-1>

撤销指定的提交或提交范围。
重置命令将“撤消”给定提交中所做的任何更改。
一个包含撤消补丁的新提交将被提交,而原始提交也将保留在历史记录中。

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

这个模式说明了哪个命令做了什么。
正如你在那里看到的,reset && checkout修改了HEAD

Enter image description here


25

git reset --mixed, --soft, 和 --hard 的区别

前提条件: 如果在你的库中对现有文件进行修改,这个更改最初被视为未暂存。要提交更改,需要将其暂存,也就是使用 git add 将其添加到索引中。在提交操作期间,已暂存的文件会被添加到索引中。

让我们举个例子:

- A - B - C (master)

HEAD 指向 C,索引与 C 匹配。

--soft

  • 当我们执行 git reset --soft B 的时候,意图是移除提交C将主分支/HEAD 指向B
  • 主分支/HEAD 现在指向B,但是索引仍然是从C改变的
  • 当执行 git status 命令时,你可以看到被索引的文件是提交C中的,并且被标记为暂存状态
  • 在这个点上执行 git commit 命令会创建一个新的提交,它具有和C相同的更改

--mixed

  • 执行 git reset --mixed B 命令。
  • 执行此命令后,主分支/HEAD 将指向B,由于使用了 mixed 标志,索引也会修改以匹配B
  • 如果此时运行 git commit 命令,则不会发生任何事情,因为索引与HEAD匹配
  • 我们仍然有工作目录中的更改,但是由于它们不在索引中,所以 git status将显示它们为未暂存状态
  • 要提交它们,您需要用 git add 将其添加到索引中,然后像平常一样提交。

--hard

  • 执行 git reset --hard B 命令。
  • 执行此命令后,主分支/HEAD 将指向B,并修改你的工作目录
  • 添加在提交C中的更改和所有未提交的更改将被删除
  • 工作副本中的文件将匹配提交B,这将导致永久丢失在提交C中进行的所有更改以及未提交的更改。

希望这些可以使用的标记与 git reset 命令的比较有助于某人明智地使用它们。有关进一步详细信息,请参阅链接1链接2


24

我验证了一种高效的方法,并且这里提供一个具体的使用示例:

如果您想永久撤销/取消最后一次提交(以及之前的每个提交,数量不限),请按以下三个步骤操作:

1:获取要到达的提交的id = SHA,当然。

$ git log

2:使用以下命令删除之前的提交记录:

$ git reset --hard 'your SHA'

3:使用-f选项将新的本地历史记录强制推送到您的起源 GitHub(最后提交跟踪将从 GitHub 历史记录中删除)

$ git push origin master -f

示例

$ git log

撤销上次提交

commit e305d21bdcdc51d623faec631ced72645cca9131 (HEAD -> master, origin/master, origin/HEAD)
Author: Christophe <blabla@bla.com>
Date:   Thu Jul 30 03:42:26 2020 +0200

U2_30 S45; updating files package.json & yarn.lock for GitHub Web Page from docs/CV_Portfolio...

现在我们想要提交到HEAD

commit 36212a48b0123456789e01a6c174103be9a11e61
Author: Christophe <blabla@bla.com>
Date:   Thu Jul 30 02:38:01 2020 +0200

First commit, new title

通过删除最后一个提交来到达之前的提交

$ git reset --hard 36212a4

HEAD is now at 36212a4 First commit, new title

检查是否正常

$ git log

commit 36212a48b0123456789e01a6c174103be9a11e61 (HEAD -> master)
Author: Christophe <blabla@bla.com>
Date:   Thu Jul 30 02:38:01 2020 +0200

    First commit, new title

$ git status

On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
 (use "git pull" to update your local branch)

nothing to commit, working tree clean

更新你在Git(Hub)上的历史记录

$ git push origin master -f

Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/ GitUser bla bla/React-Apps.git
 + e305d21...36212a4 master -> master (forced update)

检查一切是否正确

$ git status

On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

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