Git预推钩

时间:2010-11-16 16:03:10

标签: git hook

我想在每次git推送之前运行一个单元测试,如果测试失败,取消推送,但我甚至找不到预推钩,只有pre-commit和pre-rebase。

7 个答案:

答案 0 :(得分:190)

答案 1 :(得分:19)

我宁愿在pre-commit-hook中运行测试。因为提交时已经记录了更改。仅推送和拉取已记录已更改的交换信息。如果测试失败,您的存储库中已经有一个“损坏”的版本。无论你是否推动它。

答案 2 :(得分:19)

  

Git在1.8.2版本中获得了预推钩。

预推钩是我需要的预提交钩子。除了保护分支外,它们还可以提供额外的安全性以及预先提交的钩子。

关于如何使用的例子(从this nice entry获取并采用和增强)

登录vagrant,运行测试然后按

的简单示例
#!/bin/bash
# Run the following command in the root of your project to install this pre-push hook:
# cp git-hooks/pre-push .git/hooks/pre-push; chmod 700 .git/hooks/pre-push

CMD="ssh vagrant@192.168.33.10 -i ~/.vagrant.d/insecure_private_key 'cd /vagrant/tests; /vagrant/vendor/bin/phpunit'"
protected_branch='master'

# Check if we actually have commits to push
commits=`git log @{u}..`
if [ -z "$commits" ]; then
    exit 0
fi

current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')

if [[ $current_branch = $protected_branch ]]; then
    eval $CMD
    RESULT=$?
    if [ $RESULT -ne 0 ]; then
        echo "failed $CMD"
        exit 1
    fi
fi
exit 0

如您所见,该示例使用受保护的分支,即预推钩的主题。

答案 3 :(得分:13)

如果您使用命令行,最简单的方法是编写一个运行单元测试的推送脚本,如果成功,则完成推送。

修改

从git 1.8.2开始,这个答案已经过时了。请参阅manojlds上面的答案。

答案 4 :(得分:7)

没有钩子,因为推送不是修改存储库的操作。

您可以在post-receive挂钩中对接收方进行检查。那是你通常拒绝传入推送的地方。在钩子中运行单元测试可能有点密集,但这取决于你。

答案 5 :(得分:5)

记录中有一个patch to Git 1.6 that adds a pre-push hook。我不知道它是否适用于1.7。

不要乱用它,你可以运行像@kubi推荐的推送脚本。你也可以把它变成一个Rake任务,所以它在你的回购中。 ruby-git可以帮助解决这个问题。如果检查目标仓库,则只有在推送到生产仓库时才能运行测试。

最后,您可以在pre-commit挂钩中运行测试,但要检查正在提交的分支。然后,您可以拥有一个production分支,该分支在接受提交之前需要通过所有测试,但您的master并不关心。 limerick_rake在这种情况下可能很有用。

答案 6 :(得分:0)

script linked by the highly-voted answer显示pre-push hook的参数等($1是远程名称,$2网址)以及如何访问提交(行read来自stdin的结构<local ref> <local sha1> <remote ref> <remote sha1>

#!/bin/sh

# An example hook script to verify what is about to be pushed.  Called by "git
# push" after it has checked the remote status, but before anything has been
# pushed.  If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
#   <local ref> <local sha1> <remote ref> <remote sha1>
#
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).

remote="$1"
url="$2"

z40=0000000000000000000000000000000000000000

while read local_ref local_sha remote_ref remote_sha
do
    if [ "$local_sha" = $z40 ]
    then
        # Handle delete
        :
    else
        if [ "$remote_sha" = $z40 ]
        then
            # New branch, examine all commits
            range="$local_sha"
        else
            # Update to existing branch, examine new commits
            range="$remote_sha..$local_sha"
        fi

        # Check for WIP commit
        commit=`git rev-list -n 1 --grep '^WIP' "$range"`
        if [ -n "$commit" ]
        then
            echo >&2 "Found WIP commit in $local_ref, not pushing"
            exit 1
        fi
    fi
done

exit 0