Is "git push --mirror" sufficient for backing up my repository?
I'm a solo developer, working in a local Git repository. For backups, I want to send an exact copy of that repository off to another server.
Is it sufficient to do this?
git push --mirror
I'm asking because I can sometimes run this command two or three times before Git tells me "Everything up-to-date", so apparently it's not an exact mirror. It seems to be re-pushing tracking branches...?
$ git push --mirror
Counting objects: 42, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (30/30), done.
Writing objects: 100% (30/30), 5.09 KiB, done.
Total 30 (delta 17), reused 0 (delta 0)
To ssh://my/repo/url
c094a10..0eedc92 mybranch -> mybranch
$ git push --mirro开发者_如何学编程r
Total 0 (delta 0), reused 0 (delta 0)
To ssh://my/repo/url
c094a10..0eedc92 origin/mybranch -> origin/mybranch
$ git push --mirror
Everything up-to-date
What is happening, and is this a good strategy?
Edit: I don't like to use something like git bundle
or .tar.bz2
archives, because I'd like the backup to be an accessible working copy. Since my backup server is connected to the net and always on, this is a nice way to access the repository when I'm on the road.
The reason you see something pushed the second time is that --mirror
pushes a little more than you expect. Apart from your local branches, it also pushes your remote branches, because mirror implies everything. So when you push normally (or with --mirror
), mybranch
is pushed and origin/mybranch
is updated to reflect the new status on origin. When you push with --mirror
, origin/mybranch
is also pushed.
This results in the strangeness you see, and also in a worse strangeness when you pull from that remote; you would get branches named origin/origin/mybranch
etc. So it's usually best to use --mirror
for one time copies, and just use normal push (maybe with --all
) for normal uses.
To always push all branches and tags, you can update .git/config
like so:
[remote "origin"]
url = ...
fetch = ...
push = +refs/heads/*
push = +refs/tags/*
That will make a normal push similar to a mirror, except that it won't delete branches that don't exist at the source or for non-fast-forward updates.
Unfortunately, you don't get an exact copy with push. You lose your stash.
I would say this is a perfectly acceptable strategy for backing up your repository. It should perform a push to your origin remote for every ref in the repository. Making it a complete 'mirror' of your local repository.
EDIT: I've just seen your updated description in the question. It seems git is pushing your remote ref to the remote itself along with everything else. Once the push has finished, the remote ref will be updated to reflect that you have just pushed to it. This will now be out of date with the remote repository so a further push is necessary. If this doesn't satisfy you. You can delete this remote ref with
git push :origin/mybranch
and then use
git push --all
remember that this won't push any new branches you create though.
What I do is:
Setup the repo: git clone --mirror user@server:/url-to-repo.git
Then when you want to refresh the backup: git remote update
from the clone location.
This backs up all branches, including new branches that get added later, although it's worth noting that branches that get deleted do not get deleted from the clone (which for a backup may be a good thing).
From http://www.garron.me/en/bits/backup-git-bare-repo.html
I usually use git push --all
. I only use --mirror when i need to push newly created branches or I deleted some branches and dont want to name them one by one. Otherwise the push --all
usually works as I need.
In the same spirit than Amber's answer, you could:
- push to a local backup created with
git bundle
- copy that unique file to your remote server.
I've been working for a long time trying to develop a bash script to safelly backup a set of repositories from a git server to another one.
I believe the following script works properly, but I recomend testing it.
Problem statement: One has a set of repositories hosted in a server called origin. One needs to periodicaly backup all repositories to another host (called upstream), taking all branches.
Solution:
declare -a projects=("rep1 rep2 rep3 rep4")
for project in ${projects}; do
cd $project;
pwd;
git fetch --all -v;
git status -v;
for remote in `git branch -r | grep origin | grep -v /HEAD`; do
echo Remote $remote;
git checkout --track $remote ;
done;
for remote in `git for-each-ref --format '%(refname:short)' refs/heads/`; do
echo Branch $remote;
git checkout $remote;
git pull;
done
git push -v --all upstream;
cd ..;
done
In this solution, the script loops over all projects, and for each project, it does two other loops. In the first loop, the script identifies and start tracking all branches that are in the host (origin), even branches that are not tracked yet. In the second loop, the script makes pull of all branches. Finally, the script pushes all branches into new git host (upstream).
Why not just compress a copy of the .git
folder and send that off to another server?
精彩评论