Haczyki Git pre-push

115

Chciałbym uruchomić testy jednostkowe przed każdym wypychaniem git i jeśli testy się nie powiodą, anuluj wypychanie, ale nie mogę nawet znaleźć haka przed wypychaniem, jest tylko wstępne zatwierdzenie i przed rebase.

owczarek
źródło

Odpowiedzi:

14

Wolałbym raczej uruchomić test w haku poprzedzającym zatwierdzenie. Ponieważ zmiana jest już rejestrowana podczas zatwierdzania. Push and pull tylko wymiany informacji o już zarejestrowanych zmianach. Jeśli test się nie powiedzie, będziesz mieć już „zepsutą” wersję w swoim repozytorium. Niezależnie od tego, czy to naciskasz, czy nie.

ordnungswidrig
źródło
203
Generalnie się z tym zgadzam, chociaż jeśli masz zwyczaj wykonywania wielu przyrostowych zatwierdzeń do późniejszego zgniatania, a zestaw testów jest duży, może to być niepraktyczne.
Cascabel
Widzę. Dlatego sugerowałbym przeprowadzenie testów przed scaleniem z główną gałęzią, ale nie ma też podpięcia przed scaleniem. Istnieje jednak punkt zaczepienia „aktualizacja”, którego można użyć, aby zapobiec aktualizacji odniesienia w zdalnym repozytorium: „Tuż przed aktualizacją odniesienia w zdalnym repozytorium wywoływany jest punkt zaczepienia aktualizacji. Jego status wyjścia określa powodzenie lub niepowodzenie odniesienia update. Hak jest wykonywany raz dla każdego aktualizowanego odniesienia i przyjmuje trzy parametry: nazwę aktualizowanego odniesienia, nazwę starego obiektu przechowywaną w ref i nową nazwę obiektu, która ma być przechowywana w ref. "
ordnungswidrig
18
Głosowano w dół, ponieważ - choć informacyjny - całkowicie ignoruje pytanie PO.
Dembinski
1
@TheDembinski Nie powiedziałbym, że ignoruje pytanie OP. W rzeczywistości bierze to pod uwagę i mówi, że istnieje lepszy sposób, aby to zrobić, niż ten, który miał na myśli PO. Ogólnie rzecz biorąc, chciałbym otrzymać taką odpowiedź.
calder.ty
9
@ calder.ty - Nie. manojlds lepiej rozwiązuje to, co ważne. W rzeczywistości haki przed zatwierdzeniem, które uruchamiają testy, są generalnie złym pomysłem imo. Zakłada, że ​​wszystkie popełnione rzeczy muszą przejść testy. Co jest złe w przypadku typowych przepływów pracy, które koncentrują się na współpracy. Więc tak ... Nie zgadzam się; nie jest to lepszy sposób na zrobienie tego, ani też nie odpowiada na to pytanie.
Dembiński
209

Git dostał pre-pushhaczyk w 1.8.2wydaniu.

Przykładowy pre-pushskrypt: https://github.com/git/git/blob/87c86dd14abe8db7d00b0df5661ef8cf147a72a3/templates/hooks--pre-push.sample

Informacje o wydaniu 1.8.2 mówiące o nowym haku przed wypychaniem: https://github.com/git/git/blob/master/Documentation/RelNotes/1.8.2.txt

manojlds
źródło
1
@manojlds czy wiesz, do czego służy ten hak? Chciałbym go użyć do wysłania mojego pliku binarnego do moich klientów podczas wypychania do określonej gałęzi (tj. Zbuduj wersję nightly i załaduj ją z curl, przed wypchnięciem). Problem polega na tym, że budowanie i przesyłanie zajmuje trochę czasu, a zdalne zamyka połączenie. Tak więc kończę z moim plikiem binarnym zbudowanym i przesłanym do klientów, ale nie wypychanym do repozytorium, ponieważ zdalne repozytorium zamyka połączenie. Masz jakiś pomysł, jak to obejść? A może to zły pomysł w swoim katalogu głównym.
igrek
@igrek, czy znalazłeś rozwiązanie problemu z zamykaniem połączenia?
Mario Estrada
1
@MarioEstrada, tak, nie pamiętam dokładnie jak, ale zrobiłem to push dwa razy: pierwsza komenda git uruchamia testy jednostkowe, a następnie, jeśli nie rozłącza, wypycha i uruchamia kolejne wypychanie w innym wątku, jeśli pierwsze naciśnięcie razy na zewnątrz, drugi z innego wątku działa u mnie. Jeśli jedno i drugie się powiedzie, to pierwsza wpycha zmiany, a druga nic. Sztuczka polega na tym, że dodałem jakiś argument, który omija testy jednostkowe (który został użyty do drugiego wypychania git, więc nie rozpoczął testów jednostkowych ponownie)
igrek
24

Git uzyskał hak przed wypychaniem w wersji 1.8.2.

Haczyki przed wypychaniem są tym, czego potrzebowałem wraz z hakami przed zatwierdzeniem. Oprócz ochrony gałęzi mogą również zapewnić dodatkowe bezpieczeństwo w połączeniu z haczykami pre-commit.

I na przykład, jak używać (wzięte i przyjęte i ulepszone z tego fajnego wpisu )

Prosty przykład logowania się do włóczęgi, uruchamiania testów, a następnie wypychania

#!/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 [email protected] -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

Jak widać, w przykładzie zastosowano chronioną gałąź, temat haka pre-push.

Jimmy Kane
źródło
14

Jeśli korzystasz z wiersza poleceń, najłatwiejszym sposobem na to jest napisanie skryptu wypychania, który uruchamia testy jednostkowe i, jeśli się powiedzie, kończy wypychanie.

Edytować

Od wersji 1.8.2 git ta odpowiedź jest nieaktualna. Zobacz odpowiedź manojlds powyżej.

kubi
źródło
czy w ogóle nie używasz haków? wystarczy zamienić „git pull” na, na przykład, „git uinttestspull”? to nie jest dokładnie to, czego potrzebuję
sheepwalker
1
@sheepwalker: s / pull / push / i użyj aliasu, aby był ładny i krótki.
Cascabel
@sheepwalker Tak, to nie jest dokładnie to, o co prosiłeś, ale jak powiedział @calmh, nie ma haków przed wypychaniem.
kubi
8

Nie ma na to punktu zaczepienia, ponieważ wypychanie nie jest operacją modyfikującą repozytorium.

Możesz jednak zrobić kontrole po stronie odbiorczej, na post-receivehaku. To jest miejsce, w którym zwykle odrzucasz nadchodzący atak. Wykonywanie testów jednostkowych może być trochę intensywne, ale to zależy od Ciebie.

Jakob Borg
źródło
6

Dla przypomnienia, istnieje łatka do Git 1.6, która dodaje hak przed wypychaniem . Nie wiem, czy działa przeciwko 1.7.

Zamiast zadzierać z tym, możesz uruchomić skrypt push, taki jak zalecany @kubi. Możesz także uczynić z tego zadanie Rake, aby znalazło się w twoim repozytorium. ruby-git może w tym pomóc. Jeśli sprawdzisz repozytorium docelowe, możesz uruchomić testy tylko podczas wypychania do repozytorium produkcyjnego.

Na koniec możesz uruchomić testy w swoim pre-commithooku, ale sprawdź, do której gałęzi jest przypisana. Wtedy możesz mieć, powiedzmy, productiongałąź, która wymaga przejścia wszystkich testów przed zaakceptowaniem zatwierdzenia, ale ciebie masterto nie obchodzi. limerick_rake może być przydatny w tym scenariuszu.

Turadg
źródło
dzięki, właściwie już wybrałem ostatni wariant (na koniec możesz przeprowadzić testy w haku przed zatwierdzeniem ..)
sheepwalker
1

Skrypt związany przez wysoko głosowało odpowiedź pokazuje parametry itp do pre-pushhaka ( $1jest odległa nazwisko, $2adres URL) i jak uzyskać dostęp do zobowiązuje (linie readze standardowego wejścia mają strukturę <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-inc
źródło