问题
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 stash
es 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