Git 服务器端的预接收钩子,拒绝任何具有任何非线性历史记录的主机推送
我正在寻找一个shell脚本(Git 服务器端的预接收钩子,拒绝任何具有任何非线性历史记录的主机推送,git,sh,Git,Sh,我正在寻找一个shell脚本(sh,不可能是bash),它将拒绝任何具有任何非线性历史的主控 我尝试了以下脚本: 它是在ruby中实现的,但它甚至不在服务器上运行。然后我尝试了bash的等效版本: 这一个运行,但不做它应该做的(它不拒绝任何东西) 感谢您的建议。经过在sourceforge服务器上的不懈努力,我得到了以下信息: #!/bin/sh # Author: Mathieu Malaterre # This code is free software. It can be used
sh
,不可能是bash
),它将拒绝任何具有任何非线性历史的主控
我尝试了以下脚本:
它是在ruby中实现的,但它甚至不在服务器上运行。然后我尝试了bash的等效版本:
这一个运行,但不做它应该做的(它不拒绝任何东西)
感谢您的建议。经过在sourceforge服务器上的不懈努力,我得到了以下信息:
#!/bin/sh
# Author: Mathieu Malaterre
# This code is free software. It can be used and distributed under the
# same terms as git itself.
# http://stackoverflow.com/questions/5482887/how-to-avoid-merge-branch-master-of-ssh-gdcm-git-sourceforge-net-gitroot-gdc
read rev_old rev_new refname
ref_to_check="refs/heads/master"
if [ "$refname" = "$ref_to_check" ]
then
merge_bases=`git merge-base ${rev_old} ${rev_new}`
if [ "$merge_bases" != "$rev_old" ]
then
echo "Non fastward is disallowed"
exit 1
fi
# non-fast-forward case:
git rev-list --parents $merge_bases..$rev_new \
| while read x; do
set -- $x
if [ "$#" != "2" ]
then
echo "Multiple parents: $x";
exit 1
fi;
done
[ $? -ne 0 ] && exit 1
fi
exit 0
你可以做得比你的钩子简单得多
merge_commit=$(git rev-list -n 1 --merges $rev_old..$rev_new)
if [ -n "$merge_commit" ]; then
echo "Merge commit detected: $merge_commit";
exit 1
fi
您可能还希望将其设置为更新挂钩,而不是预接收挂钩。pre-receive钩子在整个push中运行一次,在stdin上获取输入,而update钩子在每个要更新的ref上运行一次,将输入作为参数。这会提供更好的粒度
#!/bin/sh
ref=$1
rev_old=$2
rev_new=$3
if [ "$ref" = refs/heads/master ]; then
...
fi
通常也不需要检查快进。Git在默认情况下已经不允许非快进推送,如果您想即使在强制推送时也拒绝它们,只需在配置中将receive.denynonfastforts
设置为true。我猜你想拒绝他们,即使是强迫他们去掌握,但允许他们去其他地方?这是一种访问控制,实际上通过gitolite之类的东西可以很好地实现,如果你自己托管,但我想如果这是你的要求,而你没有gitolite,这是你能做的最好的了
最后,我还感到奇怪的是,您允许将合并提交推送到其他引用,而不是主引用。这可能会导致一些意外,如果有人推到一个不稳定的分支,它会被测试,然后你想要它在master上-但不能推到那里 这个脚本适合我!它保护选定的分支不受强制推送和删除的影响
#!/bin/sh
_REFNAME="$(echo "${1}" | sed -e 's,[^/]\+/,,g')"
_OLDREF="${2}"
_NEWREF="${3}"
_PROTECTED_LIST=( 'master' 'develop' )
_PROTECTED=false
for ref in "${_PROTECTED_LIST[@]}"; do
if [[ "${ref}" == "${_REFNAME}" ]]; then
_PROTECTED=true
fi;
done;
echo ""
echo "#################### YOUR PROJECT NAME ####################"
echo "Branch: ${_REFNAME}"
echo "Old ref: ${_OLDREF}"
echo "New ref: ${_NEWREF}"
echo ""
_SUCCESS=true
if ${_PROTECTED}; then
_GITOUT="$(git merge-base ${_OLDREF} ${_NEWREF} 2>/dev/null)"
if [[ -n "${_GITOUT}" && "${_GITOUT}" != "${_OLDREF}" ]]; then
echo "ERROR! You can't force the push on this branch!"
_SUCCESS=false
fi;
if [[ -n "$(echo "${_NEWREF}" | sed -n -e '/^0\+$/p')" ]]; then
echo "ERROR! You can't delete this branch!"
_SUCCESS=false
fi;
fi;
if ${_SUCCESS}; then
echo "SUCCESS! :-)"
echo "See you later?"
echo ""
exit 0
fi;
echo ""
exit 1
+1个很好的答案-我希望你不介意,但我更新了链接问题中的答案,使用了
git rev list--merges
,并将属性返回到你的答案。master之外的非线性历史对我来说很好。当合并人员时,git将合并--挤压以将其放入master中。“==”是一种bash ism,因此您的脚本将只在服务器上工作,/bin/sh
实际上是bash。您应该将“==”更改为单个“=”。。。