61

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 --mirror
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.

Thomas
  • 150,847
  • 41
  • 308
  • 421
  • 2
    See also: [Backup a Local Git Repository](http://stackoverflow.com/questions/2129214/backup-a-local-git-repository) – miku Jul 26 '10 at 08:24
  • Does this backup the reflog as well? If not then this is a pretty poor backup. – onionjake Apr 07 '14 at 21:52

7 Answers7

36

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.

Jakob Borg
  • 21,033
  • 6
  • 45
  • 47
  • 1
    Thanks, that's good to know. I do recall having seen these `origin/origin/*` branches at some point, but apparently I deleted them. The problem with `--all` is that it won't push any new branches, nor will it delete any deleted branches. It's not fool-proof enough, and I can be a fool at times. There's no way to tell `--mirror` to ignore remote branches? – Thomas Jul 27 '10 at 11:20
  • I don't think there is a way to get it to ignore remotes. You could, however, modify yout `.git/config` to push more per default. I've updated the answer. – Jakob Borg Jul 27 '10 at 12:09
27

Unfortunately, you don't get an exact copy with push. You lose your stash.

Community
  • 1
  • 1
nschum
  • 14,984
  • 5
  • 56
  • 56
  • 5
    Thanks, that's good to know. It does not really matter, though, because the stash is supposed to be a really short-term thing anyway. – Thomas Jul 27 '10 at 11:15
  • 2
    Yes, I think it's good enough for backup, but not ideal for syncing. Besides, we all know how long we sometimes depend on supposedly short-term things. ;) – nschum Jul 27 '10 at 18:36
  • 6
    If you are keeping stashes for any amount of time, maybe you need to get more comfortable making branches (: – Jay Apr 23 '12 at 00:20
13

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.

Greg Sexton
  • 8,879
  • 6
  • 29
  • 34
  • Then why does it do something when I run it a second time? – Thomas Jul 26 '10 at 11:28
  • What do you mean by 'something'? Is the repository you're pushing to a bare clone? Can you provide more detail as I'm sure that git push --mirror should provide the functionality you're looking for. – Greg Sexton Jul 26 '10 at 18:23
  • 6
    Also worth knowing is cloning the repository using the --mirror option then using 'git remote add --mirror '. This will automatically mirror so you should just be able to run 'git push'. – Greg Sexton Jul 26 '10 at 18:32
5

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

fantabolous
  • 15,954
  • 5
  • 46
  • 45
4

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.

RaptorX
  • 833
  • 1
  • 8
  • 18
1

In the same spirit than Amber's answer, you could:

Community
  • 1
  • 1
VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283
0

Why not just compress a copy of the .git folder and send that off to another server?

Amber
  • 446,318
  • 77
  • 595
  • 531