【问题标题】:How do I restore a remote crashed Git repo?如何恢复远程崩溃的 Git 存储库?
【发布时间】:2013-09-30 17:22:31
【问题描述】:

好的。我们都知道,每个 repo 的克隆都可以作为克隆 repo 的备份。美好的。此外,使用git fetch 更新历史记录的每个遥控器都会备份到应用了git fetch 的存储库中。

但是当涉及到备份的恢复我该怎么做?git fetch 的正确相反命令是什么?

我的一个 Git 存储库有问题:

git status
fatal: unable to read tree 0d2f806b01ded93e76a6f2c7a68429939f483026

是的,我可以start repairing the repo somehow,但是——我很幸运——在我对notebook 的回购死亡之前,我在远程机器上做了一个git fetch notebook

所以,我在 desktop 上有一个 repo,那里有我已故 repo 的所有最新参考(如 refs/remote/notebook/fix/issue1refs/remote/notebook/master 等)。

如何使用此信息恢复 notebook 上的存储库?

【问题讨论】:

    标签: git restore git-remote


    【解决方案1】:

    我找到了一个简单的方法:

    desktop,向 git 询问 notebook 的已知远程分支:

    git branch -r | grep notebook > notebookbranches
    

    现在我们有一个名为 notebookbranches 的文件,其中包含笔记本的所有分支。

    notebook 上,创建一个名为 myrepo2 的新空仓库

    git init myrepo2
    

    将此仓库添加为远程desktop:

    git remote add myrepo2 //notebook/D$/myrepo2 # working on Windows, use share name
    git fetch myrepo2 # fetch current state of myrepo2
    

    现在,在文件notebookbranches 上打开您最喜欢的编辑器。该文件目前如下所示:

    notebook/fix/issue1
    notebook/master
    ...
    

    将文件修改为如下所示:

    git push myrepo2 -f refs/remotes/notebook/fix/issue1
    git push myrepo2 -f refs/remotes/notebook/master
    ...
    

    使这个文件可执行并执行它。

    脚本完成后,所有分支都存在于 myrepo2 存储库中,但存储在 .git/refs/remotes/notebook 下。

    将此处的所有文件移至.git/refs/heads/ 文件夹。

    那么,你就完成了。

    【讨论】:

    • 简单的方法,可能比我的简单。如果由于某种原因 refs 被打包(这可能发生在足够大的仓库中),您仍然可以使用 git for-each-ref(如下所示)在笔记本上重新创建分支名称。
    【解决方案2】:

    (1) 在桌面上,将 repo 克隆到一个临时目录中(您将在其中按照您希望它们在笔记本上的方式设置所有分支标签)。让我们使用(裸露的)--mirror 克隆来避免对工作目录大惊小怪,并节省一些空间,同时还将所有 refs 复制到一个膨胀的循环中:

    desktop$ mkdir /tmp/for_notebook; cd /tmp/for_notebook  # or similar
    desktop$ git clone --mirror /path/to/repo
    

    现在您有了/tmp/for_notebook/repo.git--bare 和/或--mirror 倾向于添加.git),设置此克隆中的所有分支标签以匹配它们在笔记本上的位置:

    desktop$ cd repo.git      # i.e., /tmp/for_notebook/repo.git
    desktop$ for refname in   # ok, now see below
    

    您可以在此处手动或通过脚本执行操作。如果分支数量很少,您可以手动列出它们:

    desktop$ for refname in fix/issue1 master; do
    > git update-ref refs/heads/$refname refs/remotes/notebook/$refname
    > done
    

    如果有很多,您可以使用 git for-each-ref 自动执行此操作,但它会为您提供需要更多 shell 脚本编写的长(ish,不妨使用完整名称):

    desktop$ for fullname in $(git for-each-ref \
    > --format '%(refname)' refs/remotes/notebook/); do
    > refname=${fullname#refs/remotes/notebook/}
    > git update-ref refs/heads/$refname $fullname
    > done
    

    此时git branch 应该只为您提供您期望的分支,但如果有额外的,您可以使用git branch -d 删除它们。

    (2) 现在将其克隆到笔记本中,作为一个新的 repo:

    notebook$ git clone ssh://desktop.name//tmp/for_notebook/repo.git repo
    

    这无疑已经建立了master 分支;你只需要添加其他分支。重新更新master 是无害的,所以,和以前一样,除了遥控器现在是origin/* 而不是for_notebook/*

    notebook$ for fullname in $(git for-each-ref \
    > --format '%(refname)' refs/remotes/origin/); do
    > refname=${fullname#refs/remotes/origin/}
    > git update-ref refs/heads/$refname $fullname
    > done
    

    此时您可能想要调整配置等,这样您就不会将desktop/tmp/for_notebook/repo.git 设置为origin。 (我通常通过直接编辑 .git/config 来做到这一点。)根据需要与笔记本的原始 repo .git/config 进行比较。

    (旧的 reflog 现在已经消失了,您保存的所有 git stashes 都没有了,因为这些都是没有被复制到 desktop 的本地 ref。)

    【讨论】:

      猜你喜欢
      • 2014-07-29
      • 1970-01-01
      • 2014-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-04
      相关资源
      最近更新 更多