Возможно, вас заинтересует ловушка обновления, которую написал Юнио и которую Карл улучшил. Поместите приведенный ниже код $GIT_DIR/hooks/updateи не забудьте включить его с помощью chmod +x.
#!/bin/bash
umask 002
# If you are having trouble with this access control hook script
# you can try setting this to true. It will tell you exactly
# why a user is being allowed/denied access.
verbose=false
# Default shell globbing messes things up downstream
GLOBIGNORE=*
function grant {
$verbose && echo >&2 "-Grant- $1"
echo grant
exit 0
}
function deny {
$verbose && echo >&2 "-Deny- $1"
echo deny
exit 1
}
function info {
$verbose && echo >&2 "-Info- $1"
}
# Implement generic branch and tag policies.
# - Tags should not be updated once created.
# - Branches should only be fast-forwarded unless their pattern starts with '+'
case "$1" in
refs/tags/*)
git rev-parse --verify -q "$1" &&
deny >/dev/null "You can't overwrite an existing tag"
;;
refs/heads/*)
# No rebasing or rewinding
if expr "$2" : '0*$' >/dev/null; then
info "The branch '$1' is new..."
else
# updating -- make sure it is a fast-forward
mb=$(git-merge-base "$2" "$3")
case "$mb,$2" in
"$2,$mb") info "Update is fast-forward" ;;
*) noff=y; info "This is not a fast-forward update.";;
esac
fi
;;
*)
deny >/dev/null \
"Branch is not under refs/heads or refs/tags. What are you trying to do?"
;;
esac
# 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"
then
rc=$(cat $allowed_users_file | grep -v '^#' | grep -v '^$' |
while read heads user_patterns
do
# does this rule apply to us?
head_pattern=${heads#+}
matchlen=$(expr "$1" : "${head_pattern#+}")
test "$matchlen" = ${#1} || continue
# if non-ff, $heads must be with the '+' prefix
test -n "$noff" &&
test "$head_pattern" = "$heads" && continue
info "Found matching head pattern: '$head_pattern'"
for user_pattern in $user_patterns; do
info "Checking user: '$username' against pattern: '$user_pattern'"
matchlen=$(expr "$username" : "$user_pattern")
if test "$matchlen" = "${#username}"
then
grant "Allowing user: '$username' with pattern: '$user_pattern'"
fi
done
deny "The user is not in the access list for this branch"
done
)
case "$rc" in
grant) grant >/dev/null "Granting access based on $allowed_users_file" ;;
deny) deny >/dev/null "Denying access based on $allowed_users_file" ;;
*) ;;
esac
fi
allowed_groups_file=$GIT_DIR/info/allowed-groups
groups=$(id -G -n)
info "The user belongs to the following groups:"
info "'$groups'"
if test -f "$allowed_groups_file"
then
rc=$(cat $allowed_groups_file | grep -v '^#' | grep -v '^$' |
while read heads group_patterns
do
# does this rule apply to us?
head_pattern=${heads#+}
matchlen=$(expr "$1" : "${head_pattern#+}")
test "$matchlen" = ${#1} || continue
# if non-ff, $heads must be with the '+' prefix
test -n "$noff" &&
test "$head_pattern" = "$heads" && continue
info "Found matching head pattern: '$head_pattern'"
for group_pattern in $group_patterns; do
for groupname in $groups; do
info "Checking group: '$groupname' against pattern: '$group_pattern'"
matchlen=$(expr "$groupname" : "$group_pattern")
if test "$matchlen" = "${#groupname}"
then
grant "Allowing group: '$groupname' with pattern: '$group_pattern'"
fi
done
done
deny "None of the user's groups are in the access list for this branch"
done
)
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" ;;
*) ;;
esac
fi
deny >/dev/null "There are no more rules to check. Denying access"
После этого вы даете определенным пользователям или группам возможность вносить изменения в репозиторий. Все, кто может его видеть, имеют доступ только для чтения.
Здесь используются два файла, $GIT_DIR/info/allowed-usersи allowed-groups, чтобы описать, в какие головы и кем можно вставлять. Формат каждого файла будет выглядеть так:
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
При этом Линус может нажимать или создавать bw/penguinor bw/zebraили bw/pandaветки, Паски может делать только cogito, а JC может делать masterи puветки и создавать теги с поддержкой версий. А tmp/blahветки делать может кто угодно . Знак «+» на puзаписи означает, что JC может выполнять на ней нажатие без перемотки вперед.
Если у этого человека еще нет доступа к хосту, на котором находится ваш репозиторий, возможно, у этого человека должен быть только git-shellдоступ, а не неограниченный доступ. Создайте специального пользователя git и в~git/.ssh/authorized_keys добавьте SSH-ключ постороннего в следующую форму. Обратите внимание, что ключ должен быть в одной длинной строке, но я заключил его ниже, чтобы облегчить представление.
no-agent-forwarding, no-port-forwarding, no-pty, no-X11-forwarding,
команда = "env myorg_git_user = joeuser / usr / local / bin / git-shell -c
\ "$ {SSH_ORIGINAL_COMMAND: -} \" "ssh-rsa AAAAB3 ... 2iQ == joeuser@foo.invalid
В зависимости от вашей локальной настройки вам может потребоваться изменить путь к файлу git-shell. Помните, что sshdочень параноидально относится к разрешениям.ssh каталога, поэтому отключите его биты групповой записи и все файлы под ним.
Включение всех пользователей через пользователя git означает, что вы должны уметь различать людей, и это цель myorg_git_userпеременной среды. Вместо того, чтобы полагаться на безусловный username=$(id -u -n), настройте ловушку обновления, чтобы использовать ее:
# Implement per-branch controls based on username
allowed_users_file=$GIT_DIR/info/allowed-users
if [ -z "$myorg_git_user" ]; then
username=$(id -u -n)
else
username=$myorg_git_user
fi
info "The user is: '$username'"
При такой настройке ваш друг с доступом только для чтения будет клонировать с помощью команды, подобной приведенной ниже. Конкретный путь будет зависеть от ваших настроек. Чтобы хороший путь заработал, либо переместите свой репозиторий в домашний каталог пользователя git, либо создайте символическую ссылку, указывающую на него.
$ git clone git@blankman.com.invalid: coolproject.git
но не сможет делать обновления.
$ git push origin mybranch
Всего 0 (дельта 0), повторно используется 0 (дельта 0)
удаленный: ошибка: хук отказался обновлять ссылки / головы / mybranch
На git@blankman.com.invalid: coolproject.git
! [удаленное отклонение] mybranch -> mybranch (крючок отклонен)
ошибка: не удалось отправить некоторые ссылки на 'git@blankman.com.invalid: coolproject.git'
Вы сказали, что работаете в командной среде, поэтому я предполагаю, что ваш центральный репозиторий был создан с этой --sharedопцией. (См core.sharedRepositoryв git configдокументации и --sharedв git initдокументации .) Убедитесь , что новый пользователь мерзавца является членом группы систем , которая дает всем вам доступ к вашему центральному хранилищу.