Git不像SVN或者CVS那样,有明确的一套权限控制方法& v( @5 T1 S2 } S; a3 X 在Git中想要实施对仓库的版本控制,大概可以有以下2个办法: + f* }' @$ d1 e 1.Git Hook:
Hooks are little scripts you can place in $GIT_DIR/hooks directory to trigger action at certain points. When git-init is run, a handful of example hooks are copied into the hooks directory of the new repository, but by default they are all disabled. To enable a hook, rename it by removing its .sample suffix
1 g9 w+ p' N7 z+ g! Z2 Z( ~
" F! ~$ z% c F& h; m2 Y git默认提供了很多类型的hooks,比如pre-commit,post-commit,post-checkout,update,pre-receive....$ d6 K/ v+ b( O' W5 o 我们可以在update的hooks中进行控制,当用户在local repository上执行git push,在remote repository更新之前,会调用该hook 该hook存放在$GIT_DIR/hooks/update下% }6 i; y+ q# j8 O/ m$ E; o " H% k& ^/ g: [+ z4 ~7 `8 j1 x 可参考http://www.kernel.org/pub/software/scm/git/docs/howto/update-hook-example.txt4 p) w8 o1 C# E0 b9 T
以下是update脚本内容,本人没有测试过是否可用) T) H F. V" B / M( f. C: R) ?8 t2 L " ^! M- p) X: r, i/ s) ?/ T0 w5 }
# If you are having trouble with this access control hook script
# you can try setting this to true. It will tell you exactly
$ E3 Y7 g1 j e' h) p! e! M; \* { # why a user is being allowed/denied access.
+ s0 [3 \/ T1 v( n verbose=false
! b5 c2 j; K! H1 X # Default shell globbing messes things up downstream
& n. T$ g' v$ m0 D7 ` GLOBIGNORE=*
7 S( E& x( n% v* b function grant {
( V+ c; S; z& X/ Q9 f6 n; Y $verbose && echo >&2 "-Grant- $1"
echo grant
exit 0
}
function info {
$verbose && echo >&2 "-Info- $1"
( d, W1 l/ K& W h- m, `+ P+ X0 o }
- R6 I; x% T1 n9 ]& }& j
# Implement generic branch and tag policies.
# - Tags should not be updated once created.
- m& C4 b% r1 T* p # - Branches should only be fast-forwarded unless their pattern starts with '+'
case "$1" in
refs/tags/*)
$ ]$ h: \- u% R) D5 P% C! n1 w- n4 \ git rev-parse --verify -q "$1" &&
deny >/dev/null "You can't overwrite an existing tag"
;;
refs/heads/*)
# No rebasing or rewinding
9 r9 \) Y4 v! R$ C if expr "$2" : '0*$' >/dev/null; then
info "The branch '$1' is new..."
2 }) y1 o$ b& T) R$ Y+ t2 W else
% I5 ]7 w0 m3 J7 g, m& f$ I; ?/ c" w # updating -- make sure it is a fast forward
& x5 c H5 u/ ]' i7 K' F. u mb=$(git-merge-base "$2" "$3")
case "$mb,$2" in
4 v% \: E4 |4 `* B5 r) f' ] "$2,$mb") info "Update is fast-forward" ;;
*) noff=y; info "This is not a fast-forward update.";;
: e$ ?( e" `5 n2 H" ]5 F; b' x esac
fi
;;
*)
& ^3 T! B' @7 }6 O deny >/dev/null \
"Branch is not under refs/heads or refs/tags. What are you trying to do?"
a" P/ l( i1 ?' U( g4 _0 b5 m8 Q ;;
esac
" o N5 B8 L: F8 q A1 P$ M& S: [
# Implement per-branch controls based on username
allowed_users_file=$GIT_DIR/info/allowed-users
username=$(id -u -n)
info "The user is: '$username'"
if test -f "$allowed_users_file"
. `, l5 G5 K1 S* [9 ?' ? then
& K( `7 H3 V: |" q) @ rc=$(cat $allowed_users_file | grep -v '^#' | grep -v '^$' |
' X* r* y1 l( r, N+ ^8 U while read heads user_patterns
do
# does this rule apply to us?
head_pattern=${heads#+}
! t# j! K* F/ s, W* s- z matchlen=$(expr "$1" : "${head_pattern#+}")
test "$matchlen" = ${#1} || continue
# if non-ff, $heads must be with the '+' prefix
) P6 C% A0 s/ Q% n( ? test -n "$noff" &&
# S k) g# w# \& b test "$head_pattern" = "$heads" && continue
- P2 ]8 E0 }3 |0 c1 c4 f, u6 F 9 S& N: Q" ~; E) ^ info "Found matching head pattern: '$head_pattern'"
for user_pattern in $user_patterns; do
' m U3 J# Z1 ?; W9 v info "Checking user: '$username' against pattern: '$user_pattern'"
matchlen=$(expr "$username" : "$user_pattern")
if test "$matchlen" = "${#username}"
( r! k9 j: L% q$ y; [& V then
grant "Allowing user: '$username' with pattern: '$user_pattern'"
fi
. P4 C$ O" K+ a done
deny "The user is not in the access list for this branch"
' {9 s; S/ s' o4 a done
$ G" M+ Y, I2 ~1 J6 f! c )
" W3 _9 {+ u/ h- B$ W case "$rc" in
grant) grant >/dev/null "Granting access based on $allowed_users_file" ;;
! |# y+ b( F4 u( p; f4 y, h deny) deny >/dev/null "Denying access based on $allowed_users_file" ;;
*) ;;
esac
fi
9 i6 d7 w2 G9 z# I
allowed_groups_file=$GIT_DIR/info/allowed-groups
$ Z, }& e! q A% r6 ^6 \ groups=$(id -G -n)
info "The user belongs to the following groups:"
. L `5 I5 s9 n& R0 { info "'$groups'"
2 n; c; C9 F1 g# A' t; d
if test -f "$allowed_groups_file"
7 p. T, u+ X6 S4 j; b" g0 G W then
rc=$(cat $allowed_groups_file | grep -v '^#' | grep -v '^$' |
while read heads group_patterns
do
' U8 s4 c/ [: C9 c # does this rule apply to us?
0 y1 T8 D( E# h head_pattern=${heads#+}
1 V2 I0 n, t+ G V matchlen=$(expr "$1" : "${head_pattern#+}")
test "$matchlen" = ${#1} || continue
2 W' U9 \/ P8 L6 Y. y3 n5 ^( O. w; p& r) T , h6 j$ r5 G$ A Q* o% d # if non-ff, $heads must be with the '+' prefix
! |% x: ^1 g! J0 { test -n "$noff" &&
test "$head_pattern" = "$heads" && continue
0 S2 S' V" M! h) z4 r# | info "Found matching head pattern: '$head_pattern'"
for group_pattern in $group_patterns; do
8 ~, A& X n8 i% {* s# V P for groupname in $groups; do
! g0 P( X4 c! }. ]/ T1 C info "Checking group: '$groupname' against pattern: '$group_pattern'"
. s* q2 Q0 ]& q3 [8 n7 @& p/ R matchlen=$(expr "$groupname" : "$group_pattern")
6 l+ A+ i/ U- G6 L if test "$matchlen" = "${#groupname}"
then
grant "Allowing group: '$groupname' with pattern: '$group_pattern'"
fi
done
5 G1 E2 c6 T" d9 h, F done
deny "None of the user's groups are in the access list for this branch"
) h, O# Z! q, Y, `( V: l, h done
3 h4 g: ~3 u- m+ A6 v )
. z! J( k9 h+ E case "$rc" in
grant) grant >/dev/null "Granting access based on $allowed_groups_file" ;;
deny) deny >/dev/null "Denying access based on $allowed_groups_file" ;;
*) ;;
; q6 a$ T, l1 O5 n7 p esac
fi
; w7 o! V( D" d* C" S i
deny >/dev/null "There are no more rules to check. Denying access"
/ p" ]0 z5 G+ P! D; L3 E -- >8 -- end of script -- >8 --
6 n: @# q6 H5 V; U6 n This uses two files, $GIT_DIR/info/allowed-users and
0 a: h3 Q8 v% S: U9 h# g) g4 S allowed-groups, to describe which heads can be pushed into by
& ^& h6 z/ k! A0 \* } whom. The format of each file would look like this:
refs/heads/master junio
+refs/heads/pu junio
refs/heads/cogito$ pasky
refs/heads/bw/.* linus
refs/heads/tmp/.* .*
refs/tags/v[0-9].* junio
; h) [2 Q. _6 Z& I* o1 t
With this, Linus can push or create "bw/penguin" or "bw/zebra"
& J" S5 Z( S V# T* ]/ \ or "bw/panda" branches, Pasky can do only "cogito", and JC can
* @( n( G; E6 r) [8 W do master and pu branches and make versioned tags. And anybody
can do tmp/blah branches. The '+' sign at the pu record means
that JC can make non-fast-forward pushes on it.
3 G) Y- Q2 X3 ~6 N * O' k E- |; p; |! s( C( } + T9 r' q k2 z. V" L 7 Z6 m2 Q. q. Q) J; U4 |2 k5 } 注意:最后需要配置$GIT_DIR/info/allowed-users和 $GIT_DIR/info/allowed-groups这2个文件,里面定义了每个user对应的可操作的分支、标签。 $ u. z3 p! d+ p* } 采用hook的方式还是比较简陋的,它要求在git服务器上为每个需要控制的用户都建立一个真实的用户,操作起来比较麻烦,而且还会衍生该用户其它的权限问题,对于一个大的团队来说,并不太合适。5 I' p* n2 v. z