Хуки предварительного нажатия в Git

115

Я хотел бы запускать модульные тесты перед каждым git push, и если тесты терпят неудачу, отменить push, но я даже не могу найти ловушку pre-push, есть только pre-commit и pre-rebase.

овчарка
источник
связанные: stackoverflow.com/questions/31681746
tkruse

Ответы:

14

Я бы предпочел запустить тест в режиме предварительной фиксации. Потому что изменение уже записано при фиксации. Push and pull только обмениваются информацией об уже записанных изменениях. Если тест не пройден, в вашем репозитории уже будет «сломанная» ревизия. Настаиваете вы на это или нет.

ordnungswidrig
источник
204
Я в целом согласен, хотя, если у вас есть привычка делать много инкрементальных коммитов для сквоша позже, а набор тестов большой, это может быть непрактично.
Cascabel
Понимаю. Поэтому я бы посоветовал провести тесты перед слиянием с основной веткой, но также нет никакого предварительного слияния. Однако есть ловушка «update», которую можно использовать для предотвращения обновления ссылки в удаленном репозитории: «Непосредственно перед обновлением ссылки в удаленном репозитории вызывается ловушка обновления. Его статус выхода определяет успех или неудачу ссылки. update. Ловушка выполняется один раз для каждой обновляемой ссылки и принимает три параметра: имя обновляемой ссылки, старое имя объекта, хранящееся в ссылке, и новое имя объекта, которое будет сохранено в ссылке ".
ordnungswidrig
18
Проголосовали против, потому что - хотя и информативно - полностью игнорируют вопрос ОП.
The
1
@TheDembinski Я бы не сказал, что он игнорирует вопрос OP. Фактически, он принимает это во внимание и говорит, что есть лучший способ сделать это, чем тот, который имел в виду OP. В общем, я бы хотел получить такой ответ.
calder.ty 01
9
@ calder.ty - Нет. Manojlds лучше обращается к тому, что имеет значение. На самом деле, хуки перед фиксацией, запускающие тесты, обычно плохая идея. Предполагается, что все, что совершается, должно проходить тесты. Что плохо для обычных рабочих процессов, ориентированных на сотрудничество. Так что да ... я не согласен; это не лучший способ сделать "это" и не решает вопрос.
The
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

manojlds
источник
1
@manojlds, знаете ли вы, для чего предназначен этот крючок? Я хотел бы использовать его, чтобы отправить свой двоичный файл своим клиентам при отправке в определенную ветку (т.е. создать ночную версию и загрузить ее с помощью curl перед отправкой). Проблема в том, что сборка и загрузка занимает некоторое время, а удаленное соединение закрывает. Таким образом, я получаю свой двоичный файл, созданный и загруженный клиентам, но не отправленный в репо, потому что удаленное репо закрывает соединение. Есть идеи, как это обойти? Или, может быть, это плохая идея в корне.
igrek
@igrek вы нашли решение проблемы с закрытием соединения?
Марио Эстрада
1
@MarioEstrada, да, я точно не помню, как, но я заставил его нажать дважды: первая команда git запускает модульные тесты, а затем, если она не отключается, она нажимает и запускает еще один толчок в другом потоке, если первый раз нажимает out, у меня работает второй из другого потока. Если первая и вторая успешны, то первая подталкивает изменения, а вторая ничего не подталкивает. Хитрость в том, что у меня был добавлен некоторый аргумент, который обходит модульные тесты (который использовался для второго git push, поэтому он не запускал модульные тесты снова)
igrek
24

В версии 1.8.2 Git получил хук предварительного нажатия.

Перехватчики pre-push - это то, что мне нужно вместе с перехватчиками pre-commit. Помимо защиты ветки, они также могут обеспечить дополнительную безопасность в сочетании с перехватчиками перед фиксацией.

И для примера того, как использовать (взято, адаптировано и улучшено из этой хорошей записи )

Простой пример входа в 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

Если вы используете командную строку, самый простой способ сделать это - написать сценарий push, который запускает ваши модульные тесты и, в случае успеха, завершает отправку.

редактировать

Начиная с git 1.8.2 этот ответ устарел. См. Ответ Manojlds выше.

куби
источник
ты имеешь в виду вообще не использовать хуки? просто замените "git pull" на, например, "git uinttestspull"? это не совсем то, что мне нужно,
овчарка
1
@sheepwalker: s / pull / push / и используйте псевдоним, чтобы сделать его красивым и коротким.
Cascabel
@sheepwalker Да, это не совсем то, о чем вы просили, но, как сказал @calmh, нет никаких предварительных нажатий.
kubi
8

Для этого нет ловушки, потому что push - это не операция, которая изменяет ваш репозиторий.

Однако вы можете делать проверки на принимающей стороне, в post-receiveкрюке. Именно здесь вы обычно отклоняете входящий push. Выполнение модульных тестов в ловушке может быть немного сложным, но это зависит от вас.

Якоб Борг
источник
6

Для записи, есть патч к Git 1.6, который добавляет ловушку pre-push . Не знаю, работает ли против 1.7.

Вместо того, чтобы возиться с этим, вы можете запустить push-скрипт, как рекомендовано @kubi. Вы также можете сделать это задачей Rake, чтобы она была в вашем репо. ruby-git может в этом помочь. Если вы проверите целевое репо, вы можете запускать тесты только при отправке в производственное репо.

Наконец, вы можете запускать тесты в своем pre-commitхуке, но проверять, к какой ветке привязаны. Тогда у вас может быть, скажем, productionветка, которая требует, чтобы все тесты прошли перед принятием фиксации, но вам masterвсе равно. limerick_rake может быть полезен в этом сценарии.

Turadg
источник
спасибо, на самом деле я уже выбрал последний вариант (наконец, вы можете запускать свои тесты в своем хуке перед фиксацией ..)
Sheepwalker 01
1

Скрипт связывает высоко-голосование ответить показывает параметры и т.д. на pre-pushкрюк ( $1это имя удаленного, $2URL) , и как получить доступ к фиксаций (строки 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
Serv-вкл
источник