如何撤销一个成功的“ Git 初选”?

在本地回购中,我刚刚执行了 git cherry-pick SHA,没有任何冲突或问题。然后我意识到我不想做我刚才做的事。我没有强迫你。

我怎样才能只摘掉这个樱桃呢?

我想知道有没有办法:

  • 当我有其他本地的变化
  • 当我没有其他本地的变化

如果可能的话,两种情况下最好使用同一个命令。

228636 次浏览

要撤消上次提交,只需执行 git reset --hard HEAD~

编辑 : 这个答案适用于该问题的早期版本,该版本没有提到保留本地更改; Tim 给出的被接受的答案确实是正确的。谢谢 Qwertzguy 的提醒。

初始选择基本上是一个提交,所以如果您想撤消它,只需撤消提交即可。

当我有其他本地的变化

隐藏当前更改,以便在重置提交后重新应用它们。

$ git stash
$ git reset --hard HEAD^
$ git stash pop  # or `git stash apply`, if you want to keep the changeset in the stash

当我没有其他本地的变化

$ git reset --hard HEAD^

git reflog可以来救你。

在控制台中键入它,您将获得一个 git 历史记录列表以及表示它们的 SHA-1。

只需检查任何 SHA-1,您希望恢复到


在回答问题之前,让我们加入一些背景知识,解释什么是 HEAD

First of all what is HEAD?

HEAD只是对当前分支上当前提交(最新)的引用。
在任何给定的时间只能有一个 HEAD(不包括 git worktree)

HEAD的内容存储在 .git/HEAD中,它包含当前提交的40字节 SHA-1。


detached HEAD

如果您不在最近的提交中——这意味着 HEAD指向历史上被称为 < em > detached HEAD 的以前的提交。

enter image description here

在命令行上,由于 HEAD没有指向当前分支的末端,因此它将看起来像这样-SHA-1而不是分支名称

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 t 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>

“移动”您的头回到所需的提交。

# 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 revert <sha-1>

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

# add 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

一个命令并且 没有使用破坏性的 git reset命令:

GIT_SEQUENCE_EDITOR="sed -i 's/pick/d/'" git rebase -i HEAD~ --autostash

它只是删除提交,即使您有本地更改,它也会将您精确地放回到初选之前的状态。

如果可能,避免硬重置。硬重置是 git 中为数不多的破坏性操作之一。幸运的是,你可以撤销一个没有重置的樱桃,并避免任何破坏性的东西。

请注意要撤消的初选的散列,假设它是 ${bad_cherrypick}。做 git revert ${bad_cherrypick}。现在,你的工作树的内容还和你那次糟糕的选择之前一样。

重复你的 git cherry-pick ${wanted_commit},当你对新的选择感到满意的时候,做一个 git rebase -i ${bad_cherrypick}~1。在重基期间,删除 ${bad_cherrypick}及其相应的还原。

您正在处理的分支将只有好的选择权。不需要重置!

面对同样的问题,我发现如果你已经提交和/或推到远程自从你成功的初选,你想删除它,你可以找到初选的 SHA 运行:

git log --graph --decorate --oneline

然后,(在使用 :wq退出日志之后)您可以使用

git rebase -p --onto YOUR_SHA_HERE^ YOUR_SHA_HERE

其中 YOUR_SHA_HERE等于精心挑选的提交的40个字符或缩写为7个字符的 SHA。

首先,您将无法推动您的更改,因为您的远程回购和您的本地回购将有不同的提交历史。可以使用以下命令强制本地提交替换远程中的内容

git push --force origin YOUR_REPO_NAME

(我从 Seth Robertson改编了这个解决方案: 参见“删除整个提交”。)