我需要创建一个预接收挂钩,拒绝任何来自任何非主服务器的客户端的推送,所以我写了这个脚本:
#!/bin/bash
refname="$0"
oldrev="$1"
newrev="$2"
alowed_branch='master'
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
if [ $alowed_branch = $current_branch ]
then
echo "you are pushing to master branch"
exit 0
else
echo Branch $current_branch is Locked.
exit 1
fi
现在我不知道如何测试它......
在预先提交时进行测试'挂钩我当地的git repo我得到了我想要的东西:
但是当尝试将其作为预推或预接收挂钩进行测试时,它不会产生任何影响,我可以在不受干扰的情况下进行推送。
有没有办法在GitHub上测试它?
答案 0 :(得分:2)
测试挂钩,特别是预接收挂钩很困难:它们在不寻常的环境中运行。几乎没有很好的方法来测试它们(主要的好方法是一个或两个牺牲的存储库)。
这里有许多相互交织的问题:
refname="$0"
无论如何都是错误的,就像在shell脚本中一样,$0
引用脚本本身的名称。
current_branch=$(refname)
您在编辑中删除的内容也是错误的:它尝试运行命令refname
。所以你替换它很好,但是:
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
这是一个巧妙的错误:如果您当前的分支名为fixes/bug-123
,它会将current_branch
设置为bug-123
,而不是fixes/bug-123
。
要将当前分支名称作为符号引用减去refs/heads/
部分,请使用:
current_branch=$(git symbolic-ref --short HEAD) || exit 1
--short
指示git symbolic-ref
省略refs/heads/
部分,|| exit 1
指示 shell 退出(失败状态) git symbolic-ref
本身失败了,它可以:如果你有一个"分离的HEAD",HEAD
不是一个符号引用,Git会抱怨这个并且current_branch
将设置为空字符串。
现在,有了这些,你提到:
...尝试将其作为推前或预接收挂钩进行测试...
作为预推钩,$1
和$2
(存储在oldrev
和newrev
中)实际上会设置为远程的名称和网址!旧的和新的修订ID以及旧的和新的引用名称将作为其标准输入传递给该挂钩。这一切都发生在客户端,在连接到其他Git(远程)之后但在发送任何内容之前。 (See the section on pre-push
hooks in the githooks documentation.)
作为预接收挂钩,$1
和$2
根本不会设置为任何(这是正常的,因为您永远不会使用变量)。 当前分支将是远程上另一个Git中的当前分支。预接收挂钩(如预推钩)必须读取其标准输入,一次一行,检查该行上提供的每组参数。如果钩子以非零返回退出,则整个推送被拒绝(从服务器端)。
在预推或预接收挂钩中检查参考名称时,请务必检查整个参考:传入参考(在任何挂钩中)或传出参考(在预推中) hook)可以引用标记,例如refs/tags/v1.2
中的标记,或者名称包含斜杠的分支,如refs/heads/feature/tall
中所示。除了名字的最后一部分之外,不要砍掉除了前两部分之外的所有部分,而不是看它们。并且,在任何一个钩子中,当前分支名称通常完全不相关:运行git push
的人指定在命令行上推送的引用:
git push origin \
refs/heads/master:refs/for/master \
refs/tags/v1.2:refs/tags/v1.2 \
refs/notes/commits:refs/notes/commits \
refs/peculiar-ref:refs/even-stranger/master
例如。这些都不会进入目标上的分支;只有一个来自来源的分支。
(请注意,钩子可以用任何可以在安装了特定Git的机器上运行的语言编写。他们不会 成为bash / sh脚本 - 但是如果你有Git你必须有一个shell,因为Git的部分是用shell编写的。总是要注意硬编码的路径:例如,在某些系统上,bash可能位于/usr/local/bin/bash
而不是/bin/bash
。)< / p>