| From: Junio C Hamano <junkio@cox.net> |
| Subject: control access to branches. |
| Date: Thu, 17 Nov 2005 23:55:32 -0800 |
| Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net> |
| Abstract: An example hooks/update script is presented to |
| implement repository maintenance policies, such as who can push |
| into which branch and who can make a tag. |
| |
| When your developer runs git-push into the repository, |
| git-receive-pack is run (either locally or over ssh) as that |
| developer, so is hooks/update script. Quoting from the relevant |
| section of the documentation: |
| |
| Before each ref is updated, if $GIT_DIR/hooks/update file exists |
| and executable, it is called with three parameters: |
| |
| $GIT_DIR/hooks/update refname sha1-old sha1-new |
| |
| The refname parameter is relative to $GIT_DIR; e.g. for the |
| master head this is "refs/heads/master". Two sha1 are the |
| object names for the refname before and after the update. Note |
| that the hook is called before the refname is updated, so either |
| sha1-old is 0{40} (meaning there is no such ref yet), or it |
| should match what is recorded in refname. |
| |
| So if your policy is (1) always require fast-forward push |
| (i.e. never allow "git-push repo +branch:branch"), (2) you |
| have a list of users allowed to update each branch, and (3) you |
| do not let tags to be overwritten, then: |
| |
| #!/bin/sh |
| # This is a sample hooks/update script, written by JC |
| # in his e-mail buffer, so naturally it is not tested |
| # but hopefully would convey the idea. |
| |
| umask 002 |
| case "$1" in |
| refs/tags/*) |
| # No overwriting an existing tag |
| if test -f "$GIT_DIR/$1" |
| then |
| exit 1 |
| fi |
| ;; |
| refs/heads/*) |
| # No rebasing or rewinding |
| if expr "$2" : '0*$' >/dev/null |
| then |
| # creating a new branch |
| ; |
| else |
| # updating -- make sure it is a fast forward |
| mb=`git-merge-base "$2" "$3"` |
| case "$mb,$2" in |
| "$2,$mb") |
| ;; # fast forward -- happy |
| *) |
| exit 1 ;; # unhappy |
| esac |
| fi |
| ;; |
| *) |
| # No funny refs allowed |
| exit 1 |
| ;; |
| esac |
| |
| # Is the user allowed to update it? |
| me=`id -u -n` ;# e.g. "junio" |
| while read head_pattern users |
| do |
| if expr "$1" : "$head_pattern" >/dev/null |
| then |
| case " $users " in |
| *" $me "*) |
| exit 0 ;; # happy |
| ' * ') |
| exit 0 ;; # anybody |
| esac |
| fi |
| done |
| exit 1 |
| |
| For the sake of simplicity, I assumed that you keep something |
| like this in $GIT_DIR/info/allowed-pushers file: |
| |
| refs/heads/master junio |
| refs/heads/cogito$ pasky |
| refs/heads/bw/ linus |
| refs/heads/tmp/ * |
| refs/tags/v[0-9]* junio |
| |
| With this, Linus can push or create "bw/penguin" or "bw/zebra" |
| or "bw/panda" branches, Pasky can do only "cogito", and I can do |
| master branch and make versioned tags. And anybody can do |
| tmp/blah branches. This assumes all the users are in a single |
| group that can write into $GIT_DIR/ and underneath. |
| |
| |
| |
| |
| |
| |
| |
| |