说我有一个包含两个目录的repo,high_level /和low_level /。 我有一个想要提交访问权限的贡献者,但我感到很舒服(他们只想)让他们触摸high_level /目录。
不得不绕过恢复疯狂的提交,这太不方便了。
是否可以在不拆分存储库的情况下执行此操作?
答案 0 :(得分:2)
可以通过预接收挂钩来实现这一点,但没有任何内置功能。</ p>
要在预接收挂钩中执行此操作,请让您的挂钩扫描建议的标签更新,例如:
#! /bin/sh
...
while read oldsha newsha fullref; do
verify $oldsha $newsha $fullref || {
echo "$fullref: $oldsha -> $newsha update rejected"
exit 1
}
done
您仍然需要编写verify()函数:
NULL_SHA1=0000000000000000000000000000000000000000 # 40 0's
reftype() {
case $1 in
$NULL_SHA1) echo none;;
*) git cat-file -t $1;;
}
verify() {
local oldsha=$1 newsha=$2 fullref=$3
local otype=$(reftype $oldsha) ntype=$(reftype $newsha)
local update_type
case $otype,$ntype in
none,*) update_type=create;;
*,none) update_type=delete;;
*,*) update_type=update;;
esac
# now if update_type is create or delete, check permissions
# but if update_type is update, check revisions
verify_$update_type $oldsha $newsha $fullref
}
(以上可以更高级,例如,可以检查带注释的标签创建/删除,并且可以检查ref-type与对象类型。)
这个“验证”只返回相应的更具体的verify_create,verify_delete或verify_update返回的内容。所以你必须写那些:
verify_create() {
local oldsha=$1 newsha=$2 fullref=$3
# only $USER = wilma is allowed to create
[ "$USER" = wilma ] && return 0
echo "you ($USER) are not allowed to create things"
return 1
}
verify_delete() {
local oldsha=$1 newsha=$2 fullref=$3
# only $USER = fred is allowed to delete
[ "$USER" = fred ] && return 0
echo "you ($USER) are not allowed to delete things"
return 1
}
现在我们归结为verify_update:
verify_update() {
local oldsha=$1 newsha=$2 fullref=$3
local shortref rev
case "$fullref" in
refs/heads/*)
# a branch
shortref=${fullref#refs/heads/}
;;
*) # everything else - only barney is allowed to do those
# (and we don't check any further)
[ "$USER" = barney ] && return 0
echo "you ($USER) are not allowed to modify $fullref"
return 1
;;
esac
# user betty is restricted on branches that do not start with betty*
# everyone else is unrestricted
[ "$USER" = betty ] || return 0
case "$shortref" in
betty*) return 0;;
esac
# 1. betty is NOT allowed to REMOVE commits, even with force-push
if [ $(git rev-list --count $newsha..$oldsha) -ne 0 ]; then
echo "commit to branch $shortref would remove some revs"
return 1
fi
# 2. betty is not allowed to make certain changes
# e.g., first we forbid merges:
if [ $(git rev-list --count --min-parents=2 \
$oldsha..$newsha) -ne 0 ]; then
echo "you ($USER) are not allowed to push a merge"
return 1
fi
# then we look at each commit
for rev in $(git rev-list $oldsha..$newsha); do
check_betty_commit $rev "$shortref" || return 1
done
}
哇,我们快到了。只需要检查贝蒂提出的变化:
check_betty_commit() {
local rev=$1 shortref="$2"
# unfortunately, pipe to a loop causes the loop to
# run in a sub-shell, so it's a bit complicated here.
git diff-tree -r --no-renames --name-only --no-commit-id $rev |
(retval=0; while read pathname; do
case "$pathname" in
forbidden/path/*)
echo "branch $shortref: $rev modifies $pathname"
retval=1
;;
esac
done
exit $retval) || return 1
}
注意:以上大部分都未经过测试。
对用户名进行硬编码也可能不太好。但如果您真的想这样做,这应该会给你一些关于如何编写脚本的想法。
顺便提一下,有一个不同的(但经过更多测试的)脚本here,它根据存储库本身的设置实现一组有限的每用户访问控制,而不是硬编码。
答案 1 :(得分:0)
我不知道有什么方法可以开箱即用。您可以编写一个钩子脚本来在主仓库中执行它,但感觉这样做的正确方法是不允许此贡献者提交到存储库。
相反,让他们提交到他们自己的存储库,然后你可以将你想要的提取到主回购。通过这种方式,您可以完全控制他的提交如何以及何时进入您的回购(如果不符合您的标准,则完全无法控制)。
如果您确实需要此功能,@ slaks建议的“子模块”功能可能会满足您的需求;您可以将“high_level”视为一个单独的项目,将其映射到“low_level”存储库中。然后他可以提交到high_level存储库,您可以将这些提交提取到low_level存储库中。见http://git-scm.com/book/en/Git-Tools-Submodules