2010-03-09 19 views
48

J'écris un crochet de pré-validation. Je veux exécuter php -l contre tous les fichiers avec l'extension .php. Cependant je suis coincé.Crochet de pré-validation Git: fichiers modifiés/ajoutés

J'ai besoin d'obtenir une liste des fichiers nouveaux/modifiés qui sont mis en scène. les fichiers supprimés doivent être exclus.

J'ai essayé d'utiliser git diff et git ls-files, mais je pense que j'ai besoin d'un coup de main ici.

+0

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

+0

C'est plutôt joli. Cependant, il ne gère pas les fichiers partiellement mis en scène. Voir mon commentaire à la réponse @ LarryH. – igorw

Répondre

31

git diff --cached --name-status montrera un résumé de ce qui est mis en scène, de sorte que vous pouvez facilement exclure les fichiers supprimés, par exemple:

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

Cela indique que a été retiré en poids-status.c a été modifié et poids-status.h dans le zone de transit (index). Donc, pour vérifier que les fichiers ne sont pas enlevés:

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

Vous devez sauter à travers des cerceaux supplémentaires pour faire face aux noms de fichiers avec des espaces dans bien (option -z à git diff et une analyse syntaxique plus intéressant)

+0

Merci, c'est un bon début.Cependant, si je change un fichier sans le mettre en scène, il est toujours affiché. Je cours git la version 1.7.0.1.147.g6d84b (construction faite sur commande récente). Je ne sais pas si c'est un comportement prévu. – igorw

+0

Cela semble étrange. Le commutateur "--cached" devrait faire en sorte qu'il ne montre que les fichiers qui ont été mis en scène: bien que je le teste avec 1.6.5, il semble surprenant que cela ait changé ... "git diff --cached" sur son Propre montrer les changements non équilibrés? – araqnid

+0

Après un certain débogage, j'ai pu le retrouver à une autre cause. Merci beaucoup! – igorw

70

Une façon d'obtenir un peu plus propre de la même liste est:

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

Ceci renvoie la liste des fichiers qui doivent être vérifiés. Mais il n'est peut-être pas judicieux d'exécuter php -l sur votre copie de travail. Si vous faites un commit partiel, c'est-à-dire que vous sélectionnez un sous-ensemble des différences entre votre jeu de travail actuel et le HEAD pour le commit, le test sera exécuté sur votre jeu de travail, mais certifiera un commit qui n'a jamais existé disque.

Pour le faire correctement, vous devez extraire toute l'image étagée dans une zone temp et y effectuer le test.

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 

Voir Building a better pre-commit hook for Git pour une autre mise en œuvre.

+4

Il est en effet possible de diriger le contenu du fichier vers 'php -l'. Et c'est ce que nous avons fini avec. Voir ici: http://github.com/phpbb/phpbb3/blob/develop-olympus/git-tools/hooks/pre-commit – igorw

+2

Pour vérifier la syntaxe d'un fichier intermédiaire, vous pouvez utiliser 'git show: FILENAME | php -l'. –

7

Voici ce que j'utilise pour mes chèques 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 

pour PHP, il ressemblera à ceci:

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

Assez bien, mais ne fonctionne pas pour les fichiers partiellement mis en forme, car il lit le fichier entier. – igorw

0

git diff --cached ne suffit pas si l'appel de validation a été spécifié avec le drapeau -a, et il n'y a aucun moyen de déterminer si ce drapeau a été jeté dans le crochet. Il serait utile que les arguments à valider soient disponibles pour l'examen.

+0

git diff --cache semble être suffisant. Cependant, je crois que si vous exécutez git status --porcelain l'intérieur de votre crochet, tous les fichiers qui seront traités ne seront pas un blanc ou un? dans la première position de la sortie. Je ne l'ai pas entièrement testé, mais jusqu'à présent, il a tenu dans toutes les conditions de mon repo, un mélange de nouveaux fichiers ajoutés et modifiés où j'essaie de valider des fichiers explicites, l'ensemble de fichiers par défaut, - un pour tout. Alors pourquoi utiliser git status au lieu de git diff? Je pense que c'est plus facile à analyser. – mpersico

+0

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

+0

' statut git --porcelain | perl -ane 'imprime $ F [1], qq (\ n) si m/^ [ACM] /' ' est une meilleure réponse. Il a l'avantage d'utiliser une option --porcelain, garantie de ne jamais changer. Utilisez votre propre analyseur si perl est trop lourd pour vous. – mpersico

7

Aucune des réponses ici ne prend en charge les noms de fichiers avec des espaces. La meilleure façon pour cela est d'ajouter le drapeau -z en combinaison avec xargs -0

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

C'est ce qui est donné par git intégré dans les échantillons (voir .git/crochets/pré-commit.sample)