如何从 git push -force 中恢复?

48

以下是发生的情况:

我有两个远程的 git 分支:masterfeature1。由于某些原因,我不得不对 feature1 分支使用 git push --force,但我不知道当我使用 git push --force 时,它也会推送 master 分支。然后,一场灾难发生了,因为我将本地的 master 分支推到了远程仓库。

幸运的是,我的本地分支离远程分支并不太远。基本上,我的远程 master 在我本地 master 前面合并了两个 pull request。

所以我的问题是:我能重新打开这个 pull request 并重新合并吗?我注意到还有合并请求的提交版本,所以我担心如果我只是做一个新的 pull request,它会搞乱一些东西?理想情况下,我只想重新执行这两个请求的合并。

是否有其他方法来从这场灾难中恢复?我学到了 --force 是一个非常非常糟糕的选择。 :(

更新,以下是发生的例子:

我有以下的分支:

master
feature1
origin/master
origin/feature1

我使用GitHub的自动合并拉取请求功能合并了两个拉取请求,但是我没有在本地机器上获取master分支。所以,我认为我的origin/master比远程主分支落后两个版本。

然后,我不小心使用了git -f push,这覆盖了远程分支,现在我失去了远程仓库中拉取请求的提交记录。

我如何恢复它而不会弄乱其他贡献者的历史记录?


可能是如何从错误的git push -f origin master中恢复?的重复问题。 - CharlesB
你很快就能(从git1.8.5,2013年第四季度开始)更加谨慎地执行git push -force命令。 - VonC
2个回答

99
当使用github时,请参考GHugo的答案,该答案提供了一个与github无关的步骤。如果您在内部(或其他非github)安装上工作,请继续阅读。
您可以通过重置到旧提交并发出另一个push -f来恢复先前观察到的master状态。涉及的步骤通常如下:
# work on local master
git checkout master

# reset to the previous state of origin/master, as recorded by reflog
git reset --hard origin/master@{1}

# at this point verify that this is indeed the desired commit.
# (if necessary, use git reflog to find the right one, and
# git reset --hard to that one)

# finally, push the master branch (and only the master branch) to the server
git push -f origin master

请注意,这将恢复远程的master到最近由git fetch或等效方法检索的状态。在您上次获取后由其他人推送的任何提交都将丢失。但是,这些提交仍将在他们的 reflogs 中可用,因此他们可以使用上述步骤恢复它们。

1
问题在于我执行了git push -f命令,覆盖了origin的master分支。而且在拉取origin/master之前就这样做了,所以如果我进行重置,它不是只会将其重置为本地的origin/master吗? - Brian
1
该命令将还原 origin/master 到 push 之前的状态。 - user4815162342
“git reset —hard origin/master@{1}” 对我不起作用:“fatal: Log for 'origin/master' only has 1 entries.” - emlai
我们不知道其他人做了什么,没错,但 OP 在集成两个 PR 后没有拉取: “然后,我没有在本地机器上拉取 master 分支。” - Guildenstern
@Guildenstern,我理解为OP没有将较新版本的远程master合并到他们的master中,而不是他们从未运行过git fetch以刷新对origin/master的本地视图。 OP(很可能)观察了他们强制推送的origin/master,这就是为什么答案中的步骤有所帮助的原因。 - user4815162342
显示剩余6条评论

55
请注意,使用Github,即使您没有将存储库克隆到本地(即没有reflog)或提交sha,您也可以使用API恢复强制推送。
首先,您必须获取强制推送之前的上一个提交sha。
curl -u <username>:<token> https://api.github.com/repos/:owner/:repo/events

然后你可以从这个 sha 创建一个分支:
curl -u <github-username>:<token> -X POST -d '{"ref":"refs/heads/<new-branch-name>", "sha":"<sha-from-step-1>"}' https://api.github.com/repos/:owner/:repo/git/refs

最后,你可以将存储库克隆到本地,并再次强制推送到主分支:
git clone repo@github
git checkout master
git reset --hard origin/<new-branch-name>
git push -f origin master

请注意,使用双因素身份验证时,您需要提供一个令牌(请参阅此处获取更多信息)。
信用:Sankara Rameswaran

1
你救了我。我现在可能要使用正则表达式从这个 JSON 文件中获取文本,除非你有其他想法,但即使数据还不可用,我已经拿回了我的数据。 - rjm27trekkie
2
你应该得到比1个赞更多的奖励!!!真是个英雄,1.5天的工作没有白费! - RichardAE
1
非常感谢。你是我的救星。再补充一件事:起初似乎命令对我不起作用。我必须创建一个Github REST API个人访问令牌来在命令中使用(curl -u name:token)。除此之外,一切都很好。 - Thomas Bui
2
在这个非常有用的答案中,还有一件事需要补充,那就是现在访问 GitHub API 时需要使用令牌,使用 curl -u <username>:<token>。请参阅 https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token。 - Rey Abolofia
当一位经验较少的同事强制推送并删除了2年的git历史记录时,这对我帮助很大。现在我正在学习如何保护分支... - brendan
救了我一命!!!当我请求 https://api.github.com/repos/:owner/:repo/events 时,返回的列表非常长,所以我使用了 https://docs.github.com/en/rest/activity/events#list-events-for-the-authenticated-user 端点来查找 SHA。 - Ali Niaki

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