How do I restore a remote crashed Git repo?

冷暖自知 提交于 2019-12-13 03:59:31

问题


Okay. We all know that every clone of a repo is good as a backup of the cloned repo. Fine. Also, every remote whose history gets updated with git fetch is backed up in that repo where git fetch was applied.

But when it comes to restore of the backup: how do I do it? What is the right opposite command of git fetch?

One of my Git repo has issues:

git status
fatal: unable to read tree 0d2f806b01ded93e76a6f2c7a68429939f483026

Yes, I could start repairing the repo somehow, but – lucky me – I did a git fetch notebook on a remote machine right before my repo on notebook died.

So, I have a repo on desktop, where I have all the latest refs of my died repo (as refs/remote/notebook/fix/issue1, refs/remote/notebook/master, etc.).

How do I restore the repo on notebook with this information?


回答1:


I found an easy way:

on desktop, ask git for the known remote branches of notebook:

git branch -r | grep notebook > notebookbranches

Now we have a file called notebookbranches that holds all the branches of the notebook.

On notebook, create a fresh empty repo called myrepo2

git init myrepo2

Add this repo as remote on desktop:

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

Now, open your favourite editor on the file notebookbranches. The file currently looks like this:

notebook/fix/issue1
notebook/master
...

Modify the file to look like this:

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

Make this file executable and execute it.

When the script has finished, all the branches are present on the myrepo2 repo but are stored under .git/refs/remotes/notebook.

Take all the files present here and move them to the .git/refs/heads/ folder.

Then, you're done.




回答2:


(1) On the desktop, clone the repo into a temp dir (where you will set all the branch labels the way you want them on the notebook). Let's use a (bare) --mirror clone to make it non-tempting to fuss with a work directory, and to save some space, while also copying all refs in one swell foop:

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

Now that you have /tmp/for_notebook/repo.git (--bare and/or --mirror tends to add .git), set all the branch labels in this clone to match where they were on the notebook:

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

Here's where you can either do things manually, or by script. If there's a small number of branches you can just list them manually:

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

If there are many, you can automate this with git for-each-ref, but it will give you long(ish, might as well just use full) names that require a little more shell scripting:

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

At this point git branch should give you just the branches you expect, but if there are extras, you can delete them with git branch -d.

(2) Now clone this to the notebook, as a new repo:

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

This will no doubt set up the master branch already; you just need to add the other branches. Re-updating master is harmless, so, same idea as before, except the remotes are now origin/* instead of 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

You probably want to tweak the config at this point, etc., so that you don't have desktop and /tmp/for_notebook/repo.git as origin. (I usually do this by just editing .git/config directly.) Compare with the notebook's original repo .git/config as needed.

(The old reflog is gone now, and any git stashes you had saved, as those were all local refs that did not get copied to desktop.)



来源:https://stackoverflow.com/questions/18999479/how-do-i-restore-a-remote-crashed-git-repo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!