2010-03-09 16 views
48

Sto scrivendo un hook pre-commit. Voglio eseguire php -l su tutti i file con estensione .php. Comunque sono bloccato.Git pre-commit hook: file modificati/aggiunti

Ho bisogno di ottenere un elenco di file nuovi/modificati che sono messi in scena. i file cancellati dovrebbero essere esclusi.

Ho provato a utilizzare git diff e git ls-files, ma penso di aver bisogno di una mano qui.

+0

http://phpadvent.org/2008/dont-commit-that-error-by-travis-swicegood – Maerlyn

+0

Molto carino. Tuttavia, non gestisce i file parzialmente gestiti. Vedi il mio commento alla risposta di @ LarryH. – igorw

risposta

31

git diff --cached --name-status mostrerà un riassunto di ciò che è messo in scena, in modo da poter escludere i file rimossi, ad esempio:

M  wt-status.c 
D  wt-status.h 

Questo indica che la WT-status.c è stato modificato e WT-status.h è stato rimosso nel area di staging (indice). Quindi, per controllare solo i file che non sono stati rimossi:

[email protected]:~/src/git <master>$ git diff --cached --name-status | awk '$1 != "D" { print $2 }' 
wt-status.c 
wt-status.h 

Si dovrà fare i salti mortali in più a che fare con nomi di file con spazi in se (opzione -z a git diff e un po 'più interessante di analisi)

+0

Grazie, è un buon inizio.Tuttavia, se cambio un file senza metterlo in scena, è ancora visualizzato. Sto eseguendo git versione 1.7.0.1.147.g6d84b (build personalizzata recente). Non sono sicuro se questo è il comportamento previsto. – igorw

+0

Sembra strano. L'opzione "--cached" dovrebbe mostrare solo i file che sono stati messi in scena: anche se sto testando questo con 1.6.5, sembra sorprendente che questo sarebbe cambiato ... fa "git diff --cached" sul suo mostrare i cambiamenti non modificati? – araqnid

+0

Dopo un po 'di debug, sono riuscito a rintracciarlo per un'altra causa. Molte grazie! – igorw

70

Un modo un po 'più ordinato di ottenere la stessa lista è:

git diff --cached --name-only --diff-filter=ACM 

Ciò restituirà l'elenco dei file che devono essere controllati.

Ma l'esecuzione di php -l sulla copia di lavoro potrebbe non essere la cosa giusta da fare. Se stai facendo un commit parziale, ovvero selezionando solo un sottoinsieme delle differenze tra il tuo working set corrente e HEAD per il commit, allora il test verrà eseguito sul tuo working set, ma certifica un commit che non è mai esistito sul tuo disco.

Per eseguire correttamente l'operazione, è necessario estrarre l'intera immagine messa in scena in un'area temporanea ed eseguire il test lì.

rm -rf $TEMPDIR 
mkdir -p $TEMPDIR 
git checkout-index --prefix=$TEMPDIR/ -af 
git diff --cached --name-only --diff-filter=ACM | xargs -n 1 -I '{}' \bin\echo TEMPDIR/'{}' | grep \\.php | xargs -n 1 php -l 

Vedere Building a better pre-commit hook for Git per un'altra implementazione.

+4

In realtà è possibile reindirizzare il contenuto del file a 'php -l'. E questo è quello con cui siamo finiti. Vedi qui: http://github.com/phpbb/phpbb3/blob/develop-olympus/git-tools/hooks/pre-commit – igorw

+2

Per verificare la sintassi di un file di staging, puoi usare 'git show: FILENAME | php -l'. –

7

Ecco quello che uso per i miei assegni Perl:

git diff --cached --name-status | while read st file; do 
     # skip deleted files 
     if [ "$st" == 'D' ]; then continue; fi 
     # do a check only on the perl files 
     if [[ "$file" =~ "(.pm|.pl)$" ]] && ! perl -c "$file"; then 
       echo "Perl syntax check failed for file: $file" 
       exit 1 
     fi 
done 

per PHP che sarà simile a questa:

git diff --cached --name-status | while read st file; do 
     # skip deleted files 
     if [ "$st" == 'D' ]; then continue; fi 
     # do a check only on the php files 
     if [[ "$file" =~ ".php$" ]] && ! php -l "$file"; then 
       echo "PHP syntax check failed for file: $file" 
       exit 1 
     fi 
done 
+2

Abbastanza buono, ma non funziona per i file parzialmente gestiti, perché legge l'intero file. – igorw

0

git diff --cached non è sufficiente se è stato specificato la chiamata commit con il flag -a, e non c'è modo di determinare se quel flag è stato gettato nel gancio. Sarebbe di grande aiuto se gli argomenti da impegnare fossero disponibili per l'esame.

+0

git diff --cached sembra essere sufficiente. Tuttavia, credo che se si esegue stato git --porea all'interno del proprio hook, tutti i file che verranno elaborati non avranno uno spazio vuoto o un? nella prima posizione dell'output. Non l'ho ancora testato completamente, ma finora ha resistito in tutte le condizioni che ho nel mio repository, un mix di nuovi file aggiunti, modificati dove cerco di impegnare file espliciti, il set predefinito di file, - un per tutto Quindi perché usare lo stato git invece di git diff? Penso che sia più facile da analizzare. – mpersico

+0

'stato git --porcelain | grep -E -v '^ [? ] '' – mpersico

+0

' stato git --porcelain | perl -ane 'stampa $ F [1], qq (\ n) se m/^ [ACM] /' ' è una risposta migliore. Ha il vantaggio di utilizzare un'opzione --porcelain, garantita per non cambiare mai. Usa il tuo parser se perl è troppo pesante per te. – mpersico

7

Nessuna delle risposte qui supporta i nomi file con spazi. Il modo migliore per che deve aggiungere il flag -z in combinazione con xargs -0

git diff --cached --name-only --diff-filter=ACM -z | xargs -0 ... 

Questo è ciò che è dato da git in incorporato campioni (vedi .git/ganci/pre-commit.sample)