dacaf17c2efe3044d6f7cc0b0ff616c6cb21a255
[git.git] / Documentation / howto / update-hook-example.txt
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.
8
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:
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
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:
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
84 For the sake of simplicity, I assumed that you keep something
85 like 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
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.
98
99
100
101
102
103
104
105