3

beside a main Git repository on a server (with Gitolite) I would like to have a possibility for each developer to set up a mirror it's own local repository. That's not difficult.

However, I want to disable git push --mirror on the main Git server repository, to prevent mistakes if a developer screw the mirroring. I think the best place is a hook, maybe the update hook. But I cannot find how to detect in a server hook, that push --mirror command has been executed on the client machine.

Client side solution is not possible because we use Eclipse Git (JGit), too.

xmedeko
  • 7,336
  • 6
  • 55
  • 85
  • http://stackoverflow.com/questions/5264968/making-git-push-respect-permissions – sehe Feb 09 '12 at 13:49
  • I want to keep all access to the main repo, pull, push, delete. Just disable push --mirror. AFAIK the filesystem access does not help me with that. – xmedeko Feb 09 '12 at 13:59

2 Answers2

2

I wouldn't try to 'patch up' security by using hooks. They weren't designed for this type of access control.

You could look at gitolite. It enables you to control access on a pre-branch basis.

See https://github.com/sitaramc/gitolite/wiki

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks for the reply. When I do push --mirror on a client, than gitolite receives commands "git-receive-pack", "git-upload-pack" which is like normal fetch and push. So I do not know how to detect push --mirror in gitolite. – xmedeko Feb 09 '12 at 14:11
  • Well, maybe it's not possible. I will have to keep push --mirror allowed and make some good backup scripts. Thanks for the reply. If no other reply will appear, I would mark your as accepted. – xmedeko Feb 09 '12 at 14:13
2

If you really wanted to do this with hooks, the hook to use would be pre-receive. You can't directly detect that it's a mirror push, because there's nothing about the data being sent that says it is, but you could be smart and get it right almost all the time. The pre-receive hook gets a list of refs to be updated, with old and new values, and if it exits with non-zero status, the entire push is aborted. Probably the main distinguishing feature of a mirror push is that it also pushes remote branches, as-is. I can't think of any normal cases you'd do this in, so you could just check for that, something like:

#!/bin/bash
while read old new ref; do
   if [[ "$ref" =~ "^refs/remotes/.*" ]]; then
        echo "You're pushing remote branches - did you use 'push --mirror'?"
        echo "Rejecting push"
        exit 1
   fi
done

Any push --mirror* would trip this hook, so it should cover you; it is of course a bit overzealous but unless you intend to maintain remote branches in your central repo, it won't matter.

*Except a really really manual one, where someone pushes from a repo with no remotes by manually specifying git push --mirror <url>, but I really hope you don't have to worry about that.


I would still recommend gitolite. It doesn't exactly let you deny mirror pushes, but it can help somewhat, and provide a lot of other helpful things. Note that gitolite does allow you to add your own hooks, so wanting to use this shouldn't stop you from getting all the gitolite goodness. If you're not going to use Gitolite, you should really, really set core.logAllRefUpdates to true in the central repo, so that if someone does get a bad push by you, you can recover.

Things related to this problem that gitolite would do for you:

  • let you restrict most developers to only be able to access key branches, and prevent them from deleting anything (use RW, not RW+ permissions), so the damage they can do is limited - deletion of branches is probably the worst part of a push --mirror
  • log access more fully, so that if someone does do damage, you can see exactly who it was and what they did, and avoid it in the future
Cascabel
  • 479,068
  • 72
  • 370
  • 318
  • Works very well, thanks a lot. Just there should be normal apostrophes in the message: `"You're pushing remote branches - did you use 'push --mirror'?" – xmedeko Feb 10 '12 at 08:40