0

I have been tasked with configuring the following setup.

Currently, we have an internal canonical repo for an opensource project. We have a post-receive hook that pushes any updates to a remote repository exposed to the public.

Joe Public can pull from the public repo.

No one pushes to the remote repo except the post-receive hook

We have quite a few users working on the code internally and I really don't want to mess with the workflow that they have already working.

internal users check the code out from the internal canonical repo and commit to the same.

external devs have to submit patches and then an internal user will commit for them (after review).

At this point we want to start allowing some external devs to have commit access to the repository.

This means making the remote repo canonical.

It also means changing the workflow for users. Unless the collective here can come up with something I am missing with regard to git.

Quick diagram of the current workflow.

INTERNAL USER.

clone from internal repo. -> monkey with code -> push to internal repo -> post-receive hook pushed to remote repo.

EXTERNAL USER.

clone from external repo. -> monkey with code -> submit patch via mailing list -> Internal User pushes code to internal repo -> post-receive hook pushed to remote repo.

NEW WORKFLOW IDEALLY!!

INTERNAL USER.

clone from internal repo. -> before clone is provided pre-receive hook makes certain we have an updated mirror from the remote -> monkey with code -> push to internal repo -> pre-receive hook proxies the commit to the remote repo and syncs the 2.

EXTERNAL USER.

clone from remote repo. -> monkey with code -> push to remote repo.

This is kind of like a multi master setup. Where you can push code to either repo and pull code from either repo.

Some other caveats.

The internal repo can push and pull from the remote repo. The remote repo cannot reach the internal repo.

What do you think?

2 Answers2

0

This is going to be a bit nasty, and there are some tools designed to do this -- but they work by "locking" all the repositories whenever anybody makes a change to any of them. In your case, I think there is a simpler method.

  1. Everybody pushes to the remote repository, period. Internal and external users both.

  2. A cron job pulls from the remote repository to the internal repo.

Suppose the remote repository is available at ssh://remote/dir/proj.git, and the internal repository is available at ssh://internal/someplace/proj.git. Add to everyone's .gitconfig:

[url "ssh://remote/dir/"]
    pushInsteadOf = "ssh://internal/someplace/"

This means than anyone who clones the internal repository still gets the nice speed of pulling from a server close by, but everyone pushes to the same remote repository. Once .gitconfig is set up this way on everyone's workstation, you only need to clone and push and pull -- no extra flags, no need to configure things.

Note that the only real benefit to a setup like this is the extra speed you get when fetching from the internal repository. There is a penalty, since the granularity of the cron job controls how quickly internal users can fetch changes -- but I really hope you don't have a bunch of monkeys typing away at the same branch.

Note about hooks

There is no hook in Git that fires when a repository is fetched from. If you want to do this kind of thing where you pull in response to a git fetch, you may be able to replace the git upload-pack with a wrapper script that synchronizes the two repositories before calling the real git upload-pack.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • Wouldn't he just be able to use a post receive hook push to the internal repository and do away with cron job? – Roman Nov 06 '12 at 01:30
  • @R0MANARMY: You could, but it creates a race condition. If people push to both repositories at the same time, someone will have to go and fix it. Besides -- what is the benefit of pushing to the internal repository? – Dietrich Epp Nov 06 '12 at 01:34
  • I agree that everyone pushes to remote. I am trying to come up with a way that will handle the "pushInsteadOf" bit at the repo level instead of the .gitconfig level. – user1757914 Nov 06 '12 at 01:40
  • I mean all the devs push to remote repository, and a hook in the remote pushes to internal (basically the opposite of what post receive hook currently does). – Roman Nov 06 '12 at 01:41
  • @R0MANARMY: In the question it states that the remote server has no access to the internal server, so a hook in the remote is not possible. – Dietrich Epp Nov 06 '12 at 01:50
  • At this point I am starting to think of a "man in the middle" type solution. Where an external user pushes to the external repo. The code that is pushed is sent to a branch instead of the main. Then the internal repo that is already canonical picks up the mail and commit's it. The post hook will then push the change to the external repo. – user1757914 Nov 06 '12 at 18:13
0

I'm in a very similar situation - and my planned approach is to try to configure the local repo to do a pre-receive hook that does a pull from the remote (with auto-accepting local merge conflicts), and a post-receive hook that pushes to the remote repo. Additionally, I plan on setting up a cron job that pulls from the remote to the local every 5 minutes or so, also autoaccepting local merges(since I cannot push from remote -> local)

This way the remote users do push-pull off their repo, but the local repo acts as the 'master', and the local users work off the local repo. I figure there's a LOT of potential issues with the auto-conflict resolution. Since our CI is set up to do a build every 15 minutes when there's a commit - problems would be found reasonably quickly. Now, how to wire all this up... I get to start that tomorrow...

Dan G
  • 1,051
  • 8
  • 14