1From: Junio C Hamano <junkio@cox.net> 2Subject: control access to branches. 3Date: Thu, 17 Nov 2005 23:55:32 -0800 4Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net> 5Abstract: An example hooks/update script is presented to 6 implement repository maintenance policies, such as who can push 7 into which branch and who can make a tag. 8 9When your developer runs git-push into the repository, 10git-receive-pack is run (either locally or over ssh) as that 11developer, so is hooks/update script. Quoting from the relevant 12section of the documentation: 13 14 Before each ref is updated, if $GIT_DIR/hooks/update file exists 15 and executable, it is called with three parameters: 16 17 $GIT_DIR/hooks/update refname sha1-old sha1-new 18 19 The refname parameter is relative to $GIT_DIR; e.g. for the 20 master head this is "refs/heads/master". Two sha1 are the 21 object names for the refname before and after the update. Note 22 that the hook is called before the refname is updated, so either 23 sha1-old is 0{40} (meaning there is no such ref yet), or it 24 should match what is recorded in refname. 25 26So if your policy is (1) always require fast-forward push 27(i.e. never allow "git-push repo +branch:branch"), (2) you 28have a list of users allowed to update each branch, and (3) you 29do not let tags to be overwritten, then: 30 31 #!/bin/sh 32 # This is a sample hooks/update script, written by JC 33 # in his e-mail buffer, so naturally it is not tested 34 # but hopefully would convey the idea. 35 36 umask 002 37 case "$1" in 38 refs/tags/*) 39 # No overwriting an existing tag 40 if test -f "$GIT_DIR/$1" 41 then 42 exit 1 43 fi 44 ;; 45 refs/heads/*) 46 # No rebasing or rewinding 47 if expr "$2" : '0*$' >/dev/null 48 then 49 # creating a new branch 50 ; 51 else 52 # updating -- make sure it is a fast forward 53 mb=`git-merge-base "$2" "$3"` 54 case "$mb,$2" in 55 "$2,$mb") 56 ;; # fast forward -- happy 57 *) 58 exit 1 ;; # unhappy 59 esac 60 fi 61 ;; 62 *) 63 # No funny refs allowed 64 exit 1 65 ;; 66 esac 67 68 # Is the user allowed to update it? 69 me=`id -u -n` ;# e.g. "junio" 70 while read head_pattern users 71 do 72 if expr "$1" : "$head_pattern" >/dev/null 73 then 74 case " $users " in 75 *" $me "*) 76 exit 0 ;; # happy 77 ' * ') 78 exit 0 ;; # anybody 79 esac 80 fi 81 done 82 exit 1 83 84For the sake of simplicity, I assumed that you keep something 85like this in $GIT_DIR/info/allowed-pushers file: 86 87 refs/heads/master junio 88 refs/heads/cogito$ pasky 89 refs/heads/bw/ linus 90 refs/heads/tmp/ * 91 refs/tags/v[0-9]* junio 92 93With this, Linus can push or create "bw/penguin" or "bw/zebra" 94or "bw/panda" branches, Pasky can do only "cogito", and I can do 95master branch and make versioned tags. And anybody can do 96tmp/blah branches. This assumes all the users are in a single 97group that can write into $GIT_DIR/ and underneath. 98 99 100 101 102 103 104 105