dacaf17c2efe3044d6f7cc0b0ff616c6cb21a255
1 From: Junio C Hamano <junkio@cox.net>
2 Subject: control access to branches.
3 Date: Thu, 17 Nov 2005 23:55:32 -0800
4 Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net>
5 Abstract: 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.
9 When your developer runs git-push into the repository,
10 git-receive-pack is run (either locally or over ssh) as that
11 developer, so is hooks/update script. Quoting from the relevant
12 section of the documentation:
14 Before each ref is updated, if $GIT_DIR/hooks/update file exists
15 and executable, it is called with three parameters:
17 $GIT_DIR/hooks/update refname sha1-old sha1-new
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.
26 So if your policy is (1) always require fast-forward push
27 (i.e. never allow "git-push repo +branch:branch"), (2) you
28 have a list of users allowed to update each branch, and (3) you
29 do not let tags to be overwritten, then:
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.
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
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
84 For the sake of simplicity, I assumed that you keep something
85 like this in $GIT_DIR/info/allowed-pushers file:
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
93 With this, Linus can push or create "bw/penguin" or "bw/zebra"
94 or "bw/panda" branches, Pasky can do only "cogito", and I can do
95 master branch and make versioned tags. And anybody can do
96 tmp/blah branches. This assumes all the users are in a single
97 group that can write into $GIT_DIR/ and underneath.