如何撤消“git push --mirror”?

Posted

技术标签:

【中文标题】如何撤消“git push --mirror”?【英文标题】:How to undo "git push --mirror"? 【发布时间】:2012-02-29 08:44:02 【问题描述】:

在一个 git/github 项目中,我正在开发一个分支。一推,它说:

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),在它提到的部分中,它解释了“问题”,并描述了处理它的主要方法... 这个问题值得加分,但作者应该受到惩罚。 【参考方案1】:

您已推送到默认推送目标 git@github.com。这意味着 git@github.com 在你的源代码库中是一个远程。

这意味着,从服务器删除的 refs 在推送后仍将在远程本地。 不要更新遥控器 (!)。

通过执行验证这一点

git branch -a

在您从(本地)推送的一侧。

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

[待续]

你可以这样做:

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

请注意,在这个版本中,我 cd 到 A - 这将是您的 github 存储库。您可以git clone --mirror git@github.com:... local_rescue 以获得合适的本地版本。

我建议您在尝试之前先熟悉该程序。在此过程中备份您的存储库永远不会有坏处。

【讨论】:

git push --mirror 清理远程分支。 refs/remotes/origin 中不会有任何不在遥控器上的东西。这是一个很好的建议,如果能奏效就好了,但不幸的是它没有。 @Jefromi:你不只是测试,因为我做过。 git 版本 1.7.4.1 呃,我也是... hrm。我创建了一个带有两个分支的玩具仓库,制作了一个裸克隆,将裸克隆添加为原始的远程,删除了其中一个分支,进行了镜像推送,分支从 refs/remotes 和 logs/refs/遥控器。 Git 版本 1.7.7.3。希望我以某种方式搞砸了,或者 OP 有你的版本。 搞笑,是不是你的遥控器在你推送之前不是最新的?我从一个刚刚从 4 分支 repo 克隆一个分支的 repo 推送。在git push --mirror origin 之后,克隆仍然包含 remotes/origin/ 中的其他分支引用(就像推送目标一样,因为它变成了镜像)。 没关系,我确实搞砸了,哎呀。这很好。 (你已经得到了我的 +1。)有趣的是,清理代码如何让你立即注意到错误!【参考方案2】:

你的情况是这样的:

- x - A - B - C (origin/master)
   \
    D - E - F (master)

你想做两件事之一,这两件事都在 Git 建议你阅读的文档中描述:

拉,然后推,给你这个:

- x - A - B - C
   \           \
    D - E - F - M (master, origin/master)

强制推送 (git push --force),给你这个:

- x - D - E - F (master, origin/master)

相反,使用git push --mirror,您基本上相当于强制推送所有内容,使远程存储库成为您本地存储库的镜像。这意味着,就像它报告的那样,删除远程上不在您的存储库中的所有内容。

编辑:sehe 的回答描述了如何恢复。如果您已经运行git remote update,这将删除它用来恢复的远程分支,那么以下可能有用。否则,一切就绪。

你最好的办法是找到从远程存储库克隆的其他人(或者如果你很幸运,你可以单独克隆一个),告诉他们不要拉/取/远程更新,然后按照该 repo 中 sehe 的说明进行操作。

如果做不到这一点,恢复将非常棘手。如果您最近与任何远程分支进行过交互,那么HEAD 的 reflog 中可能会有痕迹:

git reflog show

否则,如果删除的 ref 引用了作为任何剩余分支的祖先的提交,您可以快速重新创建它们。如果它们引用的东西不是剩余分支的祖先,你可以找到悬空提交:

git fsck

也许找出哪些分支指向它们。

【讨论】:

我有另一台计算机,其中 'git branch -a' 仍然列出所有已删除的分支。从中恢复的最佳方法是什么? @zsero:看sehe的回答。【参考方案3】:

你需要跑

git branch -a

然后你可以在那里看到所有被删除的分支。

然后签出每个条目并从中创建一个新分支。

喜欢

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

注意:对所有条目都这样做

【讨论】:

以上是关于如何撤消“git push --mirror”?的主要内容,如果未能解决你的问题,请参考以下文章

Eclipse 中撤消git push提交

如何撤消“git重置”?

如何撤消多个 git 提交? [复制]

如何撤消主目录上的 git init?

如何撤消 git svn dcommit?

如何撤消 Git 中最近的本地提交?