2010-11-16 20 views
77

Vorrei eseguire un test unitario prima di ogni push Git e se i test falliscono, annullare il push, ma non riesco nemmeno a trovare il gancio pre-push, c'è pre-commit e pre solo rebase.Git pre-push hook

risposta

20

Preferirei eseguire il test in un hook pre-commit. Perché la modifica è già stata registrata durante il commit. Spingi e tira solo le informazioni di scambio sulle modifiche già registrate. Se un test fallisce, avresti già una revisione "errata" nel tuo repository. Che tu lo stia spingendo oppure no.

+112

Generalmente sono d'accordo, anche se hai l'abitudine di fare un sacco di commit incrementali per schiacciare più tardi, e la suite di test è grande, questo potrebbe essere poco pratico. – Cascabel

+0

Vedo. Quindi suggerirei di eseguire i test prima di fondersi con il ramo principale, ma non esiste neanche un hook di pre-unione. Tuttavia esiste un hook di "aggiornamento" che può essere usato per prevenire l'aggiornamento di un ref nel repository remoto: "Appena prima di aggiornare il ref sul repository remoto, viene richiamato il hook di aggiornamento. Il suo stato di uscita determina il successo o il fallimento del ref . aggiornamento il gancio eseguita una volta per ogni ref essere aggiornato, e prende tre parametri: il nome del ref aggiornato, il nome precedente dell'oggetto memorizzate nella ref, e la nuova objectname essere memorizzati nel rif." – ordnungswidrig

+0

Ho deciso di creare la variante @ordnungswidrig - basta usare il gancio di pre-commit, causa delle revisioni "rotte". Ecco la mia variante (test php + phpUntit):

#!/bin/sh /usr/bin/php /srv/www/wf/tests/run.php /srv/www/wf/tests > /tmp/result if grep 'OK' /tmp/result then exit 0 else echo 'Your tests is failed, you cannot commit' exit 1 fi 
sheepwalker

13

Se si utilizza la riga di comando, il modo più semplice per eseguire questa operazione è scrivere uno script push che esegua i test dell'unità e, in caso di esito positivo, completa la richiesta.

Modifica

Come di git 1.8.2 questa risposta non è aggiornato. Vedere la risposta di Manojlds sopra.

+0

si fa a non significa utilizzare ganci tutti? basta sostituire "git pull" con, ad esempio, "git uinttestspull"? non è esattamente quello di cui ho bisogno: – sheepwalker

+1

@epeepwalker: s/pull/push /, e usa un alias per renderlo bello e breve. – Cascabel

+0

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

7

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

È possibile eseguire i controlli sul lato ricevente tramite il gancio post-receive. È lì che normalmente rifiuterai una spinta in arrivo. Eseguire test unitari potrebbe essere un po 'impegnativo da fare in un hook, ma dipende da voi.

5

Per la cronologia, c'è un patch to Git 1.6 that adds a pre-push hook. Non so se funzioni contro 1.7.

Anziché confondere, è possibile eseguire script push come raccomandato @kubi. Potresti anche renderlo un compito Rake, quindi è nel tuo repository. ruby-git potrebbe aiutare con questo. Se si controlla il repository di destinazione, è possibile eseguire i test solo quando si spinge al repository di produzione.

Infine, è possibile eseguire i test nel proprio hook pre-commit ma controllare per quale ramo è stato eseguito il commit. Quindi potresti avere un ramo, ad esempio production, che richiede il passaggio di tutti i test prima di accettare un commit, ma il tuo master non interessa. limerick_rake potrebbe essere utile in questo scenario.

+0

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

155

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

Esempio pre-push script: https://github.com/git/git/blob/87c86dd14abe8db7d00b0df5661ef8cf147a72a3/templates/hooks--pre-push.sample

1.8.2 note di rilascio parlando del nuovo gancio di pre-push: https://github.com/git/git/blob/master/Documentation/RelNotes/1.8.2.txt

+1

Ehi amico .. Grazie .. :) –

+0

@manojlds sai cos'è questo gancio disegnato essere usato per? Mi piacerebbe usarlo per spingere il mio binario ai miei clienti quando si spinge verso un ramo specifico (cioè costruire la versione notturna e caricarla con il ricciolo, prima di spingere). Il problema è che ci vuole un po 'di tempo per costruire e caricare, e il remoto chiude la connessione. Così finisco con il mio binario costruito e caricato sui clienti ma non trasferito su un repository, perché il repo remoto chiude la connessione. Qualche idea su come aggirare questo? O forse è una cattiva idea nella sua radice. – igrek

+0

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

17

Git ha ottenuto il gancio pre-push nella release 1.8.2.

I ganci pre-push sono ciò che mi serviva insieme ai ganci pre-commit. Oltre a proteggere un ramo, possono anche fornire una sicurezza aggiuntiva combinata con i ganci pre-commit.

E per un esempio su come utilizzare (preso e adottato e migliorato da this nice entry)

esempio semplice eseguire il login per Vagrant, eseguire test e quindi spingere

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

Come si può vedere l'esempio utilizza un ramo protetto, soggetto del gancio pre-push.

0

Il script linked by the highly-voted answer mostra i parametri ecc per il pre-push hook ($1 è nome remoto, $2 URL) e come accedere i commit (linee read da stdin hanno 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