查询在git中设置预接收挂钩

时间:2012-04-30 14:08:19

标签: git

我想设置预接收挂钩,这样做的逻辑

  • 检查是否有合并提交
  • 检查是否按新分支
  • 检查是否有多次提交。

如果存在上述任何一项,则与用户互动以与他核实他是否愿意推动更改,如果是,则推送更改,否则将其删除。

是否有可能在git中的预接收挂钩中实现上述目的?

1 个答案:

答案 0 :(得分:3)

您无法在预接收挂钩中与用户进行交互,至少一般情况下不是这样,因为用户可能在某个其他计算机上执行“ssh”,而标准输入不会发送给用户。 (您可以通过检查uid和/或用户名等来解决问题,并转出到“回调”用户的脚本。我会为您指出实验。)您可以执行所有这些检查但是。

pre-receive hook获取(在stdin上)一系列行:

<old-value> SP <new-value> SP <ref-name> LF

(引自githooks(5))。如果引用名称的格式为:

refs/heads/<branchname>

然后创建,删除或更新给定分支。如果<old-value>为40 0 s,则会创建分支;如果<new-value>为40 0 s,则会将其删除;并且它正在以其他方式更新。 (还有refs / heads / *以外的东西;请参阅git-send-email挂钩获取完整列表。)

如果正在更新分支,<old-value>是它用来指向的提交ID,<new-value>是允许更新时它将指向的提交ID(这取决于预接收挂钩更新挂钩)。

这是一个简单检测你的第二和第三种情况(加上删除)的钩子。要确定是否存在合并,您必须遍历$between中的每个转速并查看是否有合并(即,具有多个父级)。要停止提交,请退出非零而不是返回0.

#! /bin/sh

check()
{
    local old=$1 new=$2 longref=$3
    local between rev

    if expr $old : '^00*$' >/dev/null; then
        echo creating new branch ${longref#refs/heads/}
        return 0
    fi
    if expr $new : '^00*$' >/dev/null; then
        echo removing branch ${longref#refs/heads/}
        return 0
    fi
    between=$(git rev-list $old..$new)
    case "$between" in
    *$'\n'*)
        echo at least two revs
        for rev in $between; do git log -1 --oneline $rev; done
        return 0
    esac
    echo only one rev
    return 0
}

while read old new longref; do
    case $longref in
    refs/heads/*) check $old $new $longref;;
    esac
done

(您可以检查$between中的所有转速,因为它们已经被发送到远程仓库,即使您要拒绝它们也是如此。


更新:我找到了一种方法,即使在使用ssh传输时也可以使用它,这不会让你偷偷摸摸任何额外的数据。

我修改(并重命名)了check函数。在新名称get_confirmation下,它意味着找出(并返回0表示)您不希望默认允许推送的情况(并且对于允许推送的情况返回1)。

然后,在主循环中,您可以这样做:

case $longref in
refs/heads/*)
    if get_confirmation $old $new $longref; then
        case $PWD in
        *.allow.git)
            echo 'allowed via alternate path'
            ;;
        *.git)
            echo "denied ... push to ${PWD%.git}.allow.git to allow"
            exit 1
            ;;
        *)
            echo "denied, don't know where I am"
            exit 1
            ;;
        esac
    fi
    ;;
# add more cases here if desired
esac

这假定您推送到位于--bare的<{1}}克隆。

要创建允许推送的等效repo,您​​必须创建一个名称以/some/path/to/repo.git结尾的实际并行目录。该目录应包含一个从普通仓库复制的实际文件repo.allow.git;目录中的其他所有内容都可以是HEAD的符号链接:

../repo.git/<same>

cd /some/path/to mkdir repo.allow.git cd repo.allow.git ln -s ../repo.git/* . rm HEAD; cp ../repo.git/HEAD . 必须是普通文件的原因是否则HEAD不会将此视为有效的repo(如果它是指向分支的链接,则只允许它为符号链接,这是做符号参考的“老方法”。

常规git push失败,您可以git push来完成它。当然,你的用户可能会养成一直这样做的习惯,避免了这个黑客的整个目的,但也许他们不会。

这一切都假设您的远程仓库是类似Unix的主机(当然,支持符号链接)。