Git提交对存储库的一部分的访问权限

时间:2014-08-15 02:07:57

标签: git commit

说我有一个包含两个目录的repo,high_level /和low_level /。 我有一个想要提交访问权限的贡献者,但我感到很舒服(他们只想)让他们触摸high_level /目录。

不得不绕过恢复疯狂的提交,这太不方便了。

是否可以在不拆分存储库的情况下执行此操作?

2 个答案:

答案 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