Git 预推挂钩

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

102514 次浏览

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

剪辑

从 git1.8.2开始,这个答案已经过时了。

它没有挂钩,因为 push 不是修改存储库的操作。

不过,你可以在接收端的 post-receive钩子中进行检查。这时你通常会拒绝接收到的推送。在钩子中运行单元测试可能有点复杂,但这取决于您。

我宁愿在 pre-commit-hook 中运行测试。因为在提交时已记录更改。推拉只交换已记录变更的信息。如果一个测试失败了,那么您的存储库中就已经有了一个“破碎的”修订版本。不管你有没有逼我。

郑重声明,有一个 补丁到 Git 1.6,增加了一个预推钩,我不知道它是否能对抗1.7。

您可以像@kubi 推荐的那样运行 push 脚本,而不是干扰它。您也可以将其改为 Rake 任务,这样它就在您的回购中了。Ruby-git可以帮上忙。如果您检查目标回购,您可以运行测试,只有当推到生产回购。

最后,您可以在 pre-commit钩子中运行测试,但是要检查提交到哪个分支。然后,您可以有一个 production分支,它要求在接受提交之前通过所有测试,但是您的 master并不关心。在这种情况下,打油诗(limerick _ rake)可能是有用的。

Git 在 1.8.2版本中得到了 pre-push钩子。

示例 pre-push脚本: https://github.com/git/git/blob/87c86dd14abe8db7d00b0df5661ef8cf147a72a3/templates/hooks--pre-push.sample

1.8.2发布说明讨论了新的 pre-push 钩子: https://github.com/git/git/blob/master/Documentation/RelNotes/1.8.2.txt

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

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

以及一个关于如何使用的例子(从 这个不错的入口获取、采用和增强)

简单的例子,登录到流浪汉,运行测试,然后推

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

正如您可以看到的示例使用了一个受保护的分支,即 pre-push 钩子的主题。

由高票通过的答案连接的剧本显示了 pre-push钩子的参数等($1是远程名称,$2 URL)以及如何访问提交(来自 stdin 的代码行 read具有结构 <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