Git pre-push ganci


Risposte:


14

Preferisco eseguire il test in un pre-commit-hook. Perché la modifica è già registrata al momento del commit. Push e pull scambiano solo informazioni su modifiche già registrate. Se un test fallisce, avresti già una revisione "non funzionante" nel tuo repository. Che tu lo stia spingendo o meno.


203
In generale sono d'accordo, anche se hai l'abitudine di fare molti impegni incrementali per schiacciare in seguito e la suite di test è grande, questo potrebbe essere poco pratico.
Cascabel

Vedo. Quindi suggerirei di eseguire i test prima di fondersi con il ramo principale, ma non c'è nemmeno un hook pre-merge. Tuttavia esiste un hook "update" che può essere utilizzato per impedire l'aggiornamento di un ref nel repository remoto: "Appena prima di aggiornare il ref sul repository remoto, viene richiamato l'hook di aggiornamento. Il suo stato di uscita determina il successo o il fallimento del ref update. L'hook viene eseguito una volta per ogni ref da aggiornare e prende tre parametri: il nome del ref che si sta aggiornando, il vecchio nome oggetto memorizzato in ref e il nuovo objectname da memorizzare in ref. "
ordnungswidrig

18
Ha votato verso il basso perché, sebbene informativo, ignora completamente la domanda del PO.
The Dembinski

1
@ TheDembinski Non direi che ignora la domanda OP. In effetti lo prende in considerazione e dice che c'è un modo migliore per farlo rispetto al modo in cui l'OP aveva in mente. Questo è in generale il tipo di risposta che vorrei ottenere.
calder.ty

9
@ calder.ty - Nah. manojlds affronta meglio ciò che conta. In effetti, gli hook pre-commit che eseguono i test sono generalmente una cattiva idea imo. Si presuppone che tutte le cose che vengono commesse debbano superare i test. Il che è negativo per i flussi di lavoro comuni che si concentrano sulla collaborazione. Quindi sì ... non sono d'accordo; non è un modo migliore per farlo, né affronta la questione.
The Dembinski

209

Git ha ottenuto il file pre-push gancio nel 1.8.2rilascio.

Campione pre-pushScript di : https://github.com/git/git/blob/87c86dd14abe8db7d00b0df5661ef8cf147a72a3/templates/hooks--pre-push.sample

Note sulla versione 1.8.2 che parlano del nuovo hook pre-push: https://github.com/git/git/blob/master/Documentation/RelNotes/1.8.2.txt


1
@manojlds, sai per cosa è stato progettato questo gancio? Vorrei usarlo per spingere il mio binario ai miei clienti quando spingevo a un ramo specifico (cioè costruire la versione notturna e caricarla con curl, prima di spingere). Il problema è che ci vuole del tempo per creare e caricare e il telecomando chiude la connessione. Quindi finisco con il mio binario costruito e caricato per i clienti ma non inviato a un repository, perché il repository remoto chiude la connessione. Qualche idea su come aggirare questo problema? O forse è una cattiva idea nella sua radice.
igrek

@igrek hai trovato una soluzione al problema di chiusura della connessione?
Mario Estrada

1
@MarioEstrada, sì, non ricordo esattamente come, ma l'ho fatto premere due volte: il primo comando git esegue gli unit test e poi se non si disconnette spinge e avvia un altro push in un altro thread, se il primo push volte fuori, il secondo da un altro thread funziona per me. Se il primo e il secondo hanno esito positivo, il primo spinge le modifiche e il secondo non spinge nulla. Il trucco è che ho aggiunto qualche argomento, che ignora i test unitari (che è stato utilizzato per il secondo push git, quindi non ha riavviato i test unitari)
igrek

24

Git ha ottenuto il pre-push hook nella versione 1.8.2.

Gli hook pre-push sono ciò di cui avevo bisogno insieme agli hook pre-commit. Oltre a proteggere un ramo, possono anche fornire una sicurezza aggiuntiva combinata con hook pre-commit.

E per un esempio sull'utilizzo (ripreso e adottato e valorizzato da questa simpatica voce )

Semplice esempio per accedere a vagrant, eseguire test e quindi premere

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

Come puoi vedere l'esempio utilizza un ramo protetto, oggetto del pre-push hook.


14

Se stai utilizzando la riga di comando, il modo più semplice per farlo è scrivere uno script push che esegua i tuoi unit test e, se riescono, completa il push.

modificare

A partire da git 1.8.2 questa risposta è obsoleta. Vedi la risposta di manojlds sopra.


intendi non usare affatto i ganci? basta sostituire "git pull" con, ad esempio, "git uinttestspull"? non è esattamente ciò di cui ho bisogno
pastore il

1
@sheepwalker: s / pull / push /, e usa un alias per renderlo carino e breve.
Cascabel

@sheepwalker Sì, non è esattamente quello che hai chiesto, ma come ha detto @calmh, non ci sono ganci pre-push.
kubi

8

Non c'è un hook per questo, perché un push non è un'operazione che modifica il tuo repository.

Puoi fare i controlli sul lato ricevente, però, nel post-receivegancio. È qui che di solito rifiuteresti un push in arrivo. L'esecuzione di unit test potrebbe essere un po 'impegnativa da fare in un gancio, ma dipende da te.


6

Per la cronaca, c'è una patch a Git 1.6 che aggiunge un hook pre-push . Non so se funziona contro 1.7.

Invece di scherzare con questo, potresti eseguire script push come consigliato da @kubi. Puoi anche renderlo un'attività Rake, quindi è nel tuo repository. ruby-git potrebbe aiutare con questo. Se controlli il repository di destinazione, puoi eseguire i test solo quando esegui il push nel repository di produzione.

Infine, potresti eseguire i tuoi test nel tuo pre-commithook ma controllare per quale ramo è stato eseguito il commit. Quindi potresti avere, diciamo, un productionramo che richiede il superamento di tutti i test prima di accettare un commit ma a te masternon interessa. limerick_rake può essere utile in quello scenario.


grazie, in realtà ho già scelto l'ultima variante (Finalmente, potresti eseguire i tuoi test nel tuo hook pre-commit ..)
Sheepwalker

1

Lo script collegato dalla risposta altamente votata mostra i parametri ecc. pre-pushAll'hook ( $1è il nome remoto, $2URL) e come accedere ai commit (le righe readdallo stdin hanno una struttura <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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.