如何撤销成功的“git cherry-pick”操作?

179
在本地仓库中,我刚刚执行了git cherry-pick SHA命令,没有任何冲突或问题。然后我意识到我不想做刚刚做的事情。我还没有将这个更改推送到任何地方。
如何仅删除此cherry pick?
我想知道是否有一种方法可以实现以下操作:
  • 当我有其他本地更改时
  • 当我没有其他本地更改时
最好只用一个命令同时适用于两种情况。
7个回答

255

摘取操作基本上就是一个提交(commit),所以如果您想要撤销它,只需要撤销这个提交。

当我有其他本地更改时

将您当前的更改存储起来(stash),以便在重置提交后重新应用它们。

$ 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^

15
如果您不确定正在挑选哪些内容,除了问题和答案之外,您可以始终使用“cherry-pick SHA --no-commit”命令进行挑选,它将不会生成提交记录,只有更改内容,这些更改内容可以轻松检出,这对于部分挑选非常有用。 - kuskmen
7
Windows: 使用命令 "git reset --hard HEAD^" 进行重置。 - slim

47
要撤销您最后一次提交,只需执行 git reset --hard HEAD~

2
应该是 HEAD^ 或 HEAD~1。 - Andreas Wederbrand
1
它们都等同于 HEAD~(事实上,也等同于 HEAD^1) - David Deutsch
1
@DavidDeutsch 这是正确的(虽然只适用于更近版本的Git),但大写(HEAD)更加健壮:考虑 head 是现有引用的名称的不幸情况。 - jub0bs
1
@Jubobs - 好主意;我已经在我的答案中更改了大小写。 - David Deutsch
警告:这将删除任何先前的本地更改,并以不可恢复的方式执行。 - qwertzguy
1
@qwertzguy,好的发现;看时间戳,关于本地更改的内容是在我发布这个答案后一分钟添加到问题中的 :) - David Deutsch

24

git reflog 可以帮助你。

在控制台中输入它,你将得到一个包含 SHA-1 的 git 历史记录列表。

只需检出您想要还原的任何 SHA-1 即可。


在回答问题之前,让我们先了解一下什么是“HEAD”。
首先,“HEAD”是什么?
“HEAD”只是当前分支上最新提交的引用。
任何时候只能有一个“HEAD”。(不包括“git worktree”)
“HEAD”的内容存储在“.git/HEAD”文件中,并且它包含当前提交的40字节SHA-1。

detached HEAD

如果您不在最新的提交上 - 意思是HEAD指向历史记录中的先前提交,它被称为detached 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 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>

将您的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 revert <sha-1>

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

# 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 --hard - wyx

22

尽可能避免硬重置。硬重置是Git中极少数的破坏性操作之一。幸运的是,您可以通过撤消cherry-pick而不用重置来避免任何破坏性。

请注意要撤消的cherry-pick的哈希值,假设它是${bad_cherrypick}。执行git revert ${bad_cherrypick}。现在,您工作树的内容就像在坏的cherry-pick之前一样。

重复git cherry-pick ${wanted_commit},当您对新的cherry-pick满意时,执行git rebase -i ${bad_cherrypick}~1。在rebase期间,删除${bad_cherrypick}及其相应的还原。

您正在工作的分支上只会有好的cherry-pick。无需重置!


1
这应该是被接受的答案。 - Murtaza Haji

6
面对这个问题,我发现如果你在成功地挑选了樱桃并提交和/或推送到远程后,想要删除它,你可以通过运行以下命令找到樱桃挑选的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 改编了此解决方案:请参见“删除整个提交”。)

2

一条命令,而且不使用具有破坏性的 git reset 命令:

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

它只是放弃了提交,使你回到了在 cherry-pick 操作之前的状态,即使你有本地更改。


它只是放弃了提交。你认为 git reset HEAD^ 做了什么? - Tim
@TimCastelijns git reset 可以撤销提交操作,而不会放弃任何更改。我建议你阅读 https://git-scm.com/docs/git-reset。OP的问题是如何撤销一个 cherry-pick。尝试两个命令,我的命令将把您带回到 cherry-pick 之前的确切状态。git reset 将破坏您的工作树,因为它会保留 cherry-pick 的更改并且它们将和您之前存在的本地更改无法区分。 - qwertzguy
是的,抱歉,我指的是 reset --hard。它不会留下任何更改。 - Tim
1
@TimCastelijns git reset --hard 是一条破坏性命令,它将删除不相关的本地更改,并以无法恢复的方式执行!所以这不是 OP 所要求的。 - qwertzguy
3
如果你能解释一下那个 sed 命令在做什么,以及它与手动操作的区别,还有 --autostash 是干什么用的,这个答案会更有用。 - Chris Page

2
我刚刚做了3个git cherry-pick操作。为了保留前两个cherry pick,但删除第三个,最简单的方法是使用git cherry-pick --abort命令。

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