在服务器端预接收钩子,拒绝任何具有任何非线性历史记录的掌握

时间:2011-03-30 15:26:25

标签: git sh

我正在寻找一个shell脚本(sh,而不是bash),拒绝任何具有任何非线性历史记录的 master 的推送。

我尝试了以下脚本:

How to avoid "Merge branch 'master' of ssh://gdcm.git.sourceforge.net/gitroot/gdcm/gdcm"

ruby中实现,但它甚至不在sourceforge服务器上运行。我尝试了bash等价物:

https://fedorahosted.org/fedora-infrastructure/attachment/ticket/1342/pre-receive

这个运行,但没有做它应该做的事情(它不会拒绝任何东西)。

感谢您的建议。

3 个答案:

答案 0 :(得分:3)

你可以做得这么多,比你的钩子更简单。

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

您也可能希望将其设为更新挂钩,而不是预先接收挂钩。预接收挂钩为整个推送运行一次,在stdin上输入,而更新挂钩每次ref运行一次以进行更新,将输入作为参数。这样可以提供更好的粒度。

#!/bin/sh
ref=$1
rev_old=$2
rev_new=$3
if [ "$ref" = refs/heads/master ]; then
    ...
fi

通常也无需检查快进。 Git默认情况下不允许非快进推送,如果你想在强制推送时拒绝它们,只需在配置中将receive.denyNonFastForwards设置为true即可。我想你甚至想强迫他们去掌握它们,但是在其他地方允许它们吗?这是一种实际上通过gitolite这样的东西很好地实现的访问控制,如果你正在做自己的托管,但我想如果这是你的要求并且你没有gitolite,这是你能做的最好的。

最后,它也让我感到奇怪,你将允许将合并提交推送到其他引用,而不是主。这可能会导致一些意外,如果有人推送到不稳定的分支,它会接受测试,然后你想要它在主人身上 - 但不能把它推到那里!

答案 1 :(得分:2)

在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

答案 2 :(得分:0)

此脚本对我有用!它可以保护选定的分支免遭强制推送和删除。

#!/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