Gitプレプッシュフック


115

すべてのgitプッシュの前に単体テストを実行したいと思います。テストが失敗した場合は、プッシュをキャンセルしますが、事前プッシュフックも見つからず、事前コミットと事前リベースしかありません。


回答:


14

私はむしろテストをpre-commit-hookで実行したいと思います。コミット時に変更がすでに記録されているためです。プッシュおよびプルは、すでに記録された変更に関する情報のみを交換します。テストが失敗した場合、リポジトリにはすでに「壊れた」リビジョンがあります。それを押しているかどうか。


203
私は概ね同意しますが、後でスカッシュするために多くの増分コミットを行う習慣があり、テストスイートが大きい場合、これは実用的ではない可能性があります。
Cascabel 2010年

そうですか。したがって、メインブランチとマージする前にテストを実行することをお勧めしますが、マージ前フックもありません。ただし、リモートリポジトリの参照の更新を防ぐために使用できる「更新」フックがあります。「リモートリポジトリの参照を更新する直前に、更新フックが呼び出されます。その終了ステータスによって、参照の成功または失敗が決まります。更新。フックは、更新される各参照に対して1回実行され、3つのパラメーターを取ります。更新される参照の名前、参照に格納されている古いオブジェクト名、および参照に格納される新しいオブジェクト名です。
ordnungswidrig 2010年

18
有益であるものの、OPの質問を完全に無視するため、反対票が投じられました。
デンビンスキー2017年

1
@TheDembinski OPの質問を無視するとは言いません。実際、それは考慮に入れられており、OPが考えていた方法よりも優れた方法があると述べています。それは一般に私が得たい種類の答えです。
calder.ty 2017年

9
@ calder.ty-いや。manojldsは、重要な問題により適切に対処します。実際、テストを実行するpre-commitフックは一般的に悪い考えです。コミットされるすべてのものがテストに合格する必要があると想定しています。これは、共同作業に焦点を当てた一般的なワークフローでは良くありません。そうそう...私は同意しません。「それ」を実行するためのより良い方法でも、質問への対応でもありません。
デンビンスキー2017年

209

Gitはリリースでpre-pushフックを取得し ました1.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 14年

@igrek接続を閉じる問題の解決策を見つけましたか?
マリオエストラーダ

1
@MarioEstrada、はい、正確に覚えていませんが、2回プッシュしました。最初のgitコマンドは単体テストを実行し、切断されない場合はプッシュし、別のスレッドで別のプッシュを開始します。アウト、別のスレッドからの2番目のものは私のために働きます。最初と2番目のいずれかが成功した場合、最初の変更は変更をプッシュし、2番目は何もプッシュしません。トリックは、ユニットテストをバイパスするいくつかの引数が追加されたことです(2回目のgit pushに使用されたため、ユニットテストは再開されませんでした)
igrek

24

Gitは1.8.2リリースでpre-pushフックを取得しました。

事前プッシュフックは、事前コミットフックと共に必要なものです。ブランチを保護するだけでなく、プリコミットフックと組み合わせて追加のセキュリティを提供することもできます。

そして、使用方法の例として(この素晴らしいエントリから採用され、拡張されました)

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

ご覧のとおり、例ではpre-pushフックの対象である保護されたブランチを使用しています。


14

コマンドラインを使用している場合、これを行う最も簡単な方法は、ユニットテストを実行するプッシュスクリプトを記述し、成功した場合はプッシュを完了することです。

編集する

git 1.8.2以降、この回答は古くなっています。上記のmanojldsの回答を参照してください。


フックをまったく使用しないという意味ですか?たとえば、「git pull」を「git uinttestspull」に置き換えますか?それはまさに私が必要としているものではありません
シープウォーカー

1
@sheepwalker:s / pull / push /、そしてエイリアスを使用して、簡潔で簡潔にします。
Cascabel 2010年

@sheepwalkerええ、それはまさにあなたが求めたものではありませんが、@ calmhが言ったように、プレプッシュフックはありません。
kubi

8

プッシュはリポジトリを変更する操作ではないので、フックはありません。

ただし、post-receiveフックで受信側のチェックを行うことができます。これは通常、着信プッシュを拒否する場所です。単体テストを実行することは、フックで行うには少し集中的かもしれませんが、それはあなた次第です。


6

記録として、プレプッシュフックを追加するGit 1.6のパッチがあります。それが1.7に対して機能するかどうかはわかりません。

それを台無しにするのではなく、@ kubi推奨のようなプッシュスクリプトを実行できます。代わりにRakeタスクにすることもできるので、リポジトリにあります。ruby-gitはこれに役立ちます。ターゲットリポジトリをチェックすると、本番リポジトリにプッシュするときにのみテストを実行できます。

最後に、pre-commitフックでテストを実行し、どのブランチがコミットされているかを確認できます。次に、たとえば、productionコミットを受け入れる前にすべてのテストに合格する必要があるが、master気にしないブランチを持つことができます。limerick_rakeはそのシナリオで役立つ場合があります。


おかげで、実際には最後のバリアントを既に選択しています(最後に、コミット前のフックでテストを実行できます。)
シープウォーカー

1

高投票回答によってリンクされたスクリプトに示したパラメータなどpre-pushのフックは$1リモートの名前であり、$2そしてどのように(行のコミットにアクセスするためのURL)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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.