Git预推钩


Answers:


14

我宁愿在提交前进行测试。因为更改已在提交时记录下来。推和拉仅交换有关已记录更改的信息。如果测试失败,则您的存储库中已经有一个“损坏的”修订版。无论您是否推动它。


203
我一般都同意,尽管如果您习惯以后要进行大量增量提交以进行压榨,并且测试套件很大,那么这可能是不切实际的。
卡斯卡贝尔

我懂了。因此,我建议测试在与主分支合并之前运行,但是也没有预合并钩子。但是,可以使用“更新”挂钩来阻止更新远程存储库中的ref:“仅在更新远程存储库上的ref之前,才会调用update挂钩。其退出状态决定了ref的成功或失败。该挂钩对每个要更新的引用执行一次,并采用三个参数:要更新的引用的名称,存储在引用中的旧对象名称和要存储在引用中的新对象名称。”
ordnungswidrig

18
投反对票的原因是-尽管内容丰富-但它完全忽略了OP的问题。
Dembinski

1
@TheDembinski我不会说它忽略了OP问题。实际上,它考虑了这一点,并说比OP想到的方法更好。通常,这就是我想要获得的答案。
calder.ty

9
@ calder.ty-不。manojlds可以更好地解决重要问题。实际上,运行测试的预提交钩子通常是个坏主意。它假设所有提交的东西都必须通过测试。这对于专注于协作的常见工作流程不利。所以...我不同意;它不是执行“ it”的更好方法,也不是解决问题的方法。
Dembinski

209

Git pre-push1.8.2发布中获得了成功 。

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

1.8.2关于新的预推钩子的发行说明:https : //github.com/git/git/blob/master/Documentation/RelNotes/1.8.2.txt


1
@manojlds你知道这个钩子是用来做什么的吗?在推送到特定分支时,我想用它来将二进制文件推送给客户(即构建夜间版本,并在推送之前使用curl上载它)。问题在于构建和上传需要花费一些时间,并且远程关闭连接。因此,我最终构建了我的二进制文件并上传给客户,但没有推送到存储库,因为远程存储库关闭了连接。任何想法如何解决这个问题?或从根本上讲,这是一个坏主意。
igrek 2014年

@igrek是否找到解决连接关闭问题的方法?
马里奥·埃斯特拉达

1
@MarioEstrada,是的,我不记得具体怎么做,但是我把它推送了两次:第一个git命令运行单元测试,然后如果它没有断开连接,它将推送并在另一个线程中启动另一个推送,如果第一个推送次数出来,另一个线程的第二个线程对我有用。如果第一个和第二个都成功,则第一个推送将更改,而第二个则不进行任何操作。诀窍是我添加了一些参数,绕过了单元测试(用于第二次git push,因此它没有再次启动单元测试)
igrek 2015年

24

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

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


14

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

编辑

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


您是说完全不使用钩子吗?只是用“ git uinttestspull”代替“ git pull”?那不是我真正需要的
牧羊人

1
@sheepwalker:s / pull / push /,并使用别名使其简短。
卡斯卡贝尔

@sheepwalker是的,这不完全是您要的,但是就像@calmh所说的那样,没有预推钩子。
kubi

8

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

但是,您可以在post-receive挂钩中在接收方进行检查。那是您通常会拒绝传入的推送的地方。运行单元测试可能需要花很多时间才能完成,但这取决于您。


6

作为记录,Git 1.6有一个补丁,其中添加了一个预推钩子。我不知道它是否适用于1.7。

您可以运行@kubi推荐的推送脚本,而不用为此烦恼。您也可以改为使其成为Rake任务,因此它位于您的存储库中。ruby-git可以帮助解决这个问题。如果检查目标存储库,则只能在推送到生产存储库时运行测试。

最后,您可以在pre-commit挂钩中运行测试,但要检查提交到哪个分支。然后,您可能会有一个production分支,例如,它要求所有测试通过之后才能接受提交,但您master不在乎。limerick_rake在这种情况下可能很有用。


谢谢,实际上我已经选择了最后一个变量(最后,您可以在提交前的钩子中运行测试。)
Sheepwalker 2011年

1

高投票答案链接脚本显示了pre-push挂钩的参数等($1是远程名称,$2URL)以及如何访问提交(readstdin中的行具有结构<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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.