views:

69

answers:

2

We have a two tier setup.

We have a primary repository (called 'primary' below).

And a secondary repository (called 'secondary' below) that was created like so:

$ git clone --bare --shared $REPO_A/primary secondary.git

People working on the secondary repository view the branches which originated from the primary repository as read only but base their own branches off these branches.

We want to sync up the secondary repository with the primary repository once a day.

I.e. we want commits and new branches that were pushed to the primary to become visible to people working off the secondary repository (next time they do a pull).

We do not want this to be symmetric, i.e. activity against the secondary repository will not become visible to those working off the primary repository.

Ideally I'd like to run a cron job that runs on the machine with the bare secondary repository that somehow fetches new data from the primary and automatically includes it into the secondary.

I was hoping there might be a simple way to do this (and I'm hoping someone here will tell me there is).

If I were to write a script to do it, it would do:

  • Create a fresh clone of the secondary.

    $ git clone $REPO_B/secondary
    $ cd secondary
    
  • Get all its branches.

    $ git branch -r | sed 's?.*origin/??'
    
  • Get all branches in the primary repo.

    $ git ls-remote --heads $REPO_A/primary | sed 's?.*refs/heads/??'
    
  • For each primary branch for which I don't already have a corresponding secondary branch:

    $ git fetch $REPO_A/primary $BRANCHNAME:$BRANCHNAME
    $ git push origin $BRANCHNAME:refs/heads/$BRANCHNAME
    
  • For each primary branch for which I already have a corresponding secondary branch:

    $ git checkout -b $BRANCHNAME --track origin/$BRANCHNAME
    $ git pull $REPO_A/primary $BRANCHNAME
    $ git push
    

As I'm new to git I wouldn't be surprised if I've failed to consider certain fundamental issues?

And like I said I'm hoping there's a simpler way of doing this, i.e. someone goes "oh, don't do all that, just do...".

Thanks,

/George

+1  A: 

You can just do a git clone --bare --mirror and periodically do a git fetch to make this happen.

I do it realtimish using a tool called gitmirror I wrote in node.js that I run on a machine at home to receive webhooks from github as well as ad-hoc hooks to sync up commits.

For a non-github example, I have a repo that's used for a couchdb backup that has a commit about once an hour. The cron job basically comes down to this:

# do some backup stuff
git commit -qam "Backup `date`" >> dump.log 2>&1

From there, I have a post-commit hook (.git/hooks/post-commit) that looks like this:

#!/bin/sh
curl -sS http://my.home.machine/gitmirror/bak/repo-name.git

You can accomplish the same thing by pushing from the receiving side. This has the advantage of firing-and-forgetting the payload in the normal case.

Dustin
Edit: Added `--bare` to the clone line since VonC reminded me. Usually I do it and realize I didn't do `--bare` and then either manually convert it or do it again.
Dustin
Interesting backup options (and a more detailed answer than mine). +1
VonC
VonC's suggestion seems to do what I want. However I feel bad - as I haven't really given Dustin's suggestion a chance on the basis that I can't find anything that explains the --mirror option in a _meaningful_ manner.E.g. the git-clone man page says no more than "Set up a mirror of the remote repository. This implies --bare."But what does this mean lifecycle wise etc? How is a repository cloned with --mirror different from one that isn't? Surprisingly Google-ing didn't enlighten me :(
George Hawkins
`--mirror` basically instructs git to set up the repo to exactly mirror the original. This means you won't have separate remote and local branches -- only exactly what's on the other side (I also see that it implies `--bare` now, so that was a useless edit)
Dustin
+1  A: 

Oh, don't do all that, just do:

git --bare fetch

;)

(See this old thread for instance)
If you have added the relevant remote origins to your bare repo, you can fetch in turn each of those origins.

VonC
This looks like what I want. Thanks for the links - from these I got to: `$ cd secondary.git; git --bare fetch origin '+refs/heads/*:refs/heads/*'`As a veteran UNIX hacker I always like to really understand what I'm at. However most Git documentation seems to be for really simple Alice and Bob cases, and anything more complex is presented cookbook style. Can you recommend a good _in-depth_ book or Web documentation for Git?
George Hawkins
@George: yes: http://www.newartisans.com/2008/04/git-from-the-bottom-up.html, although http://stackoverflow.com/questions/315911/git-for-beginners-the-definitive-practical-guide offers many other interesting links. http://tom.preston-werner.com/2009/05/19/the-git-parable.html is nice too.
VonC
Also note that those ref specs are in your git config, so with `fetch = +refs/*:refs/*`, you just have to type `git fetch`
Dustin