如何撤销"git push --mirror"操作?

21

我正在一个Git/GitHub项目的分支上工作。在push操作后,出现了以下提示:

git push
To git@github.com:...
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:...'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

我尝试解决这个问题,通过谷歌搜索后我找到了这一行代码:

git push --mirror

我执行了以下命令,现在似乎已经从服务器上删除了很多分支。

Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:...
 - [deleted]         develop
 + 797beee...bafbc50 master -> master (forced update)
 - [deleted]         milestone
 - [deleted]         robot
 - [deleted]         strategy
 * [new branch]      origin/HEAD -> origin/HEAD
 * [new branch]      origin/develop -> origin/develop
 * [new branch]      origin/master -> origin/master
 * [new branch]      origin/milestone -> origin/milestone
 * [new branch]      origin/robot -> origin/robot
 * [new branch]      origin/robot_simulator -> origin/robot_simulator
 * [new branch]      origin/strategy -> origin/strategy
 * [new branch]      origin/vision -> origin/vision

您能告诉我发生了什么,以及我如何撤消我所做的更改吗? (如果我删除了那些分支)


你知道的,如果你查看 git push --help(也就是 man git-push),在其中一个章节中它提到了这个“问题”,并描述了处理它的主要方法... - Cascabel
6
这个问题值得得分,但作者应受惩罚。 - joeytwiddle
3个回答

14

你将代码推送到了默认的远程推送目标git@github.com,这意味着git@github.com是你的源代码仓库中的远程仓库。

这意味着,从服务器上删除的引用在推送后仍会保留在本地远程仓库中。 不要更新远程仓库

可以通过执行以下操作进行验证:

git branch -a

在你推送的一侧(本地)。

它可能会显示从远程服务器删除的引用。

[待续]

你可以尝试这样做:

for-each-ref refs/remotes/origin | while read sha type name
do 
    git branch "rescue_$(basename "$name")" "$sha"
done

为了在本地恢复分支,它们将以 rescue_ 为前缀命名,这只是一种预防措施(以防出现有趣的或冲突的引用名称)。

使用你的远程仓库的名称替换 origin


测试脚本

如果您想在受控环境中测试该过程,这里是我的最小步骤方法(在空目录中执行,例如 /tmp/work)。

git init A; (cd A; touch test; git add test; git commit -m initial; git branch test1; git branch test2; git branch test3)
git clone A B
(cd B; git push --mirror origin; git branch -a)
cd A
git for-each-ref refs/remotes/origin | while read sha type name; do git branch "rescue_$(basename "$name")" "$sha"; done
git branch -a

请注意在这个版本中,我会进入A - 这将是您的 github 代码库。您可以运行 git clone --mirror git@github.com:... local_rescue 命令获得适当的本地版本。

我建议你在尝试之前先熟悉这个过程。备份存储库永远不会有坏处。


git push --mirror 清理远程分支。在 refs/remotes/origin 中不会有任何不在远程的内容。这是一个好建议,如果它能够起作用就更好了,但不幸的是它并不能。 - Cascabel
@Jefromi:你没有测试过,因为我测试过了。Git版本1.7.4.1。 - sehe
嗯,我也是这样... 嗯。我创建了一个带有两个分支的玩具仓库,进行了一个裸克隆,将裸克隆作为原始仓库的远程仓库添加进去,删除了其中一个分支,进行了镜像推送,然后在refs/remotes和logs/refs/remotes中分支就消失了。Git版本为1.7.7.3。希望要么是我搞砸了,要么OP有你的版本。 - Cascabel
有趣,是不是你们在推送之前没有更新你们的远程分支?我从一个单独的仓库推送了代码,它只克隆了一个四个分支的仓库的其中一个分支。在 git push --mirror origin 之后,该克隆仓库仍然包含 remotes/origin/ 中的其他分支引用(由于它成为了镜像,因此推送目标也是如此)。 - sehe
没关系,我搞砸了,哎呀。这很好。(你已经得到我的+1了。)有趣的是,清理代码让你立刻注意到错误! - Cascabel
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/7439/discussion-between-sehe-and-jefromi - sehe

4
你现在处于这样的情况:
- x - A - B - C (origin/master)
   \
    D - E - F (master)

您想要做两件事情,这两件事情都在Git建议您阅读的文档中有所描述:

  • Pull, then push, giving you this:

    - x - A - B - C
       \           \
        D - E - F - M (master, origin/master)
    
  • Force push (git push --force), giving you this:

    - x - D - E - F (master, origin/master)
    
相反,使用 git push --mirror 命令,您基本上相当于强制推送所有内容,将远程仓库变成了本地仓库的一个镜像。这意味着,就像它所报告的那样,删除了在你的仓库中不存在的远程仓库中的所有内容。
编辑:sehe的回答描述了如何恢复。如果您已经运行了 git remote update,这将删除它用来恢复的远程分支,则以下内容可能有用。否则,您已经全部准备好了。
最好的办法是找到已经从远程仓库克隆的其他人(或者如果你幸运的话,一个你自己分离的克隆),告诉他们不要拉取/获取/远程更新,并按照sehe的指示从该仓库进行操作。
如果没有成功,恢复将非常棘手。如果您最近与任何远程分支交互过,那么 HEAD 的reflog 中可能会有一些痕迹。
git reflog show

否则,如果被删除的引用指向的提交是其余分支的祖先,您可以快速重新创建它们。如果它们指向的不是剩余分支的祖先,则可以找到悬挂提交:
git fsck

也许可以找出哪些有分支指向它们的。


我有另一台电脑,其中“git branch -a”仍然列出所有已删除的分支。 从中恢复的最佳方法是什么? - hyperknot
@zsero:看看sehe的回答。 - Cascabel

-1
你需要运行。
git branch -a

在此输入图像描述 然后您可以在那里看到所有已删除的分支。

之后,检出每个条目并从中创建一个新分支。

就像这样

git checkout remotes/origin/endpoint
git checkout -b res_endpoint

注意:对所有条目都执行此操作。

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