撤销一个'git push'操作

817

这是我在我的“本该稳定”的分支上所做的...

% git rebase master
First, rewinding head to replay your work on top of it...
Fast-forwarded alpha-0.3.0 to master.
% git status
# On branch alpha-0.3.0
# Your branch is ahead of 'origin/alpha-0.3.0' by 53 commits.
#
nothing to commit (working directory clean)
% git push
Fetching remote heads...
  refs/
  refs/heads/
  refs/tags/
  refs/remotes/
'refs/heads/master': up-to-date
updating 'refs/heads/alpha-0.3.0'
  from cc4b63bebb6e6dd04407f8788938244b78c50285
  to   83c9191dea88d146400853af5eb7555f252001b0
    done
'refs/heads/unstable': up-to-date
Updating remote server info

后来我意识到那完全是个错误。我想撤消整个过程,将alpha-0.3.0分支还原为之前的状态。

我该怎么做?


这个StackOverflow的帖子也许可以帮到你:https://dev59.com/WnVC5IYBdhLWcg3w9GLM - Steen
8
撤销一个变基操作和撤销一个 Git 推送并不是完全相同的情况。前者只涉及到本地仓库,而后者涉及到远程仓库,并且可能会因为你所拥有的访问权限而更加棘手。 - CB Bailey
Steen - 你是对的 - 我可能应该这样做。我想,所有拉取的祝福存储库更多是一个管理任务,因此属于这里,而一般客户端 git 则是一个 stackoverflow 问题。 - khosrow
快速澄清 - 我猜如果您使用部分哈希值引用git提交,git会假定您正在谈论哈希以该字符串开头的提交? - Gershom Maes
17个回答

1278

在你回溯历史之前,确保没有其他用户获取了不正确的更改或试图在要删除的提交之上构建。

然后你需要“强制”推送旧引用。

git push -f origin last_known_good_commit:branch_name

或在您的情况下

git push -f origin cc4b63bebb6:alpha-0.3.0

你可能在远程仓库上设置了receive.denyNonFastForwards,如果是这种情况,你会收到一个包含[remote rejected]短语的错误。

在这种情况下,你将不得不删除并重新创建分支。

git push origin :alpha-0.3.0
git push origin cc4b63bebb6:refs/heads/alpha-0.3.0

如果这个方法不起作用 - 可能是因为你设置了receive.denyDeletes,那么你必须直接访问仓库。在远程仓库中,你需要执行以下类似的管道命令。

git update-ref refs/heads/alpha-0.3.0 cc4b63bebb6 83c9191dea8

25
完美并且解释得很清楚 - 非常感谢。对于任何其他看到这篇文章的人,出于学术原因,我尝试了前两种方法,两种都可行 - 显然,如果第一种方法有效,那么它是最简洁的方法。如果我能给Charles点赞10次,我会这么做。 :) - khosrow
160
方便参考,这里的第一行是 git push -f origin last_known_good_commit:branch_name。该命令用于将本地的 last_known_good_commit 提交强制推送到名为 branch_name 的远程分支 origin 上。请注意,此操作可能会破坏其他人的工作,请谨慎使用。 - philfreo
7
git push -f origin cc4b63bebb6:alpha-0.3.0 => 这个命令可以帮助我们。请注意,alpha-0.3.0是分支名称,cc4b63bebb6是我们希望回滚到的提交ID。执行此命令后,我们将处于cc4b63bebb6提交ID中。 - kumar
28
如果您正在使用共享代码库,那么这种解决方案非常危险。作为最佳实践,应将推送到共享远程存储库的所有提交视为“不可变”。请改用“git revert”:http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#fixing-mistakes - Saboosh
3
与其他所有工具相比,Git 是功能最丰富、效率最高的源代码控制工具。每个团队都使用它的方式不同。值得花一个周末尝试新的代码库,并经历所有常见情况。一旦你花了些时间来使用它,开发就会变得更加轻松。 - user1491819
显示剩余5条评论

221

我相信你也可以这样做:

git checkout alpha-0.3.0
git reset --hard cc4b63bebb6
git push origin +alpha-0.3.0

这个方法与上一个方法非常相似,区别在于您无需在远程仓库中进行操作。


14
我也用这个方法成功了,但值得注意的是这会在远程端“重写”历史记录。这可能是你想要的,但也可能不是! - Tom
4
感谢这个回答,它真的帮了我很多。我也想补充一点(并澄清一下),就是“--hard”参数后面的提交ID应该是您想将分支重置到的任何提交的ID。 - Michael Dautermann
1
重新编写了历史...任何可以拉取更改的人,我只是确保他们执行了 git reset --hard [commit_id],以便我们不会干扰时空连续性。 - Alien Life Form
11
在 "git push origin +alpha-0.3.0" 中,"+" 的作用是强制推送,即使这可能会覆盖远程存储库中的某些更改。 - jpierson
3
@jpierson 中的 + 强制进行推送,类似于 -f(但有些不同:https://dev59.com/MV8e5IYBdhLWcg3wPYhA#25937833)。如果不加它,如果您尝试 git push origin alpha-0.3.0 推送将会失败:Updates were rejected because the tip of your current branch is behind - A__
显示剩余3条评论

132

git revert比这里建议的一些方法不那么危险:

prompt> git revert 35f6af6f77f116ef922e3d75bc80a4a466f92650
[master 71738a9] Revert "Issue #482 - Fixed bug."
 4 files changed, 30 insertions(+), 42 deletions(-)
prompt> git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)
prompt>

用你自己的提交替换35f6af6f77f116ef922e3d75bc80a4a466f92650。


2
我该如何生成35f6af6f77f116ef922e3d75bc80a4a466f92650 ID?如果您能解释一下,那么这个答案会更好。 - Volomike
4
@Volomike(以及未来的开发人员),这个问题描述了许多获取当前提交哈希值的方式:在stackoverflow上有关版本控制和哈希问题的问答 - Jaime
这是正确的答案,因为使用“git reset”时,您不应该能够推送(更新被拒绝,因为当前分支的顶端落后于其远程对应项),或者您需要强制拉取,这并不是真正干净的方法。 - Thomas Decaux
这对我来说是有效的。但是要小心,因为还原操作将还原本地文件中的所有更改。 - user1941537
对于初学者:git revert 只会撤销你指定的一个提交。它不会将你的提交恢复到与指定的提交完全匹配的状态。要实现这一点,请使用 git restore 命令。 - Josiah Yoder
显示剩余2条评论

55
一种方法可以做到不会丢失你想要的更改:
git reset cc4b63b 
git stash
git push -f origin alpha-0.3.0
git stash pop

那么你可以选择你想要推送的文件


38
git push origin +7f6d03:master

这将使您的仓库回滚到指定的提交编号


4
这是最直接的答案。你救了我一命。 - Ekundayo Blessing Funminiyi
4
请记住,这不会重置您的本地文件。 - Kerem
这正是我所需要的,因为我想简单地撤消推送操作而不丢失本地更改。 - Hashim Aziz
这个答案应该在顶部!简单易懂。 - GTodorov
年,对我来说是个好年份。 - Sheldon Wei

37

2
你具体要提供哪些指令?你似乎只有旧的链接。 - jww

35
git reset --hard HEAD^
git push origin -f

这将从您的本地设备以及Github中删除最后一次提交。


1
只是为了明确,git reset --hard 是一个危险的命令。任何之前挂起的暂存区和工作目录的更改都将被重置以匹配提交树的状态。这意味着任何挂起的工作都将丢失。 - nico_lrx

25

另一种方法:

  1. 创建另一个分支
  2. 使用 "git checkout" 在该分支上检出先前提交的版本
  3. 推送新分支。
  4. 删除旧分支并推送删除 (使用 git push origin --delete <branch_name>)
  5. 将新分支重命名为旧分支
  6. 再次推送。

4
当你的代码库中已经存在错误提交时,这个看起来像是真正解决方案的东西。 - Illarion Kovalchuk

19

场景1: 如果您想撤销最后一次提交,比如 8123b7e04b3,请使用以下命令(此方法适用于我):

git revert 8123b7e04b3

git push origin +8123b7e04b3^:<branch_name>

输出结果如下:

Total 0 (delta 0), reused 0 (delta 0)
To https://testlocation/code.git
 + 8123b7e...92bc500 8123b7e04b3^ -> master (forced update)

注意:要更新更改以使其应用于您的本地代码(同时也要在本地删除提交):

$ git reset --hard origin/<branchName>
Message displayed is :    HEAD is now at 8a3902a comments_entered_for_commit

额外信息: 情况2:在某些情况下,您可能希望通过先前的命令撤消刚刚撤消的操作(基本上是撤消“撤消”),然后使用以下命令:

git reset --hard 8123b7e04b3
git push

输出:

HEAD is now at cc6206c Comment_that_was_entered_for_commit

更多信息请查看:https://github.com/blog/2019-how-to-undo-almost-anything-with-git


1
方案1应该是被接受的答案,因为问题没有指定要删除哪个提交。被接受的答案仅会删除最后一个提交,而这个答案则可以删除任何一个提交。 - Dominic Cerisano

17

撤销多个提交

git reset --hard 0ad5a7a6(只提供提交的SHA1哈希值)

撤销最后一个提交

git reset --hard HEAD~1(将更改删除到最后一个提交) git reset --soft HEAD~1(最后一次提交的更改将作为未提交的本地修改保存)


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