2010-03-09 17 views
48

Estoy escribiendo un enganche de precompromiso. Quiero ejecutar php -l contra todos los archivos con la extensión .php. Sin embargo, estoy atascado.Gancho de precompilación de Git: Archivos modificados/agregados

Necesito obtener una lista de archivos nuevos/modificados que están en etapas. los archivos eliminados deben ser excluidos

He intentado usar git diff y git ls-files, pero creo que necesito ayuda.

+0

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

+0

Eso es bastante agradable. Sin embargo, no maneja archivos parcialmente en etapas. Vea mi comentario a la respuesta de @ LarryH. – igorw

Respuesta

31

git diff --cached --name-status mostrará un resumen de lo que está por etapas, por lo que se puede excluir fácilmente archivos eliminados, por ejemplo:

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

Esto indica que el WT-status.c fue modificado y peso-status.h fue retirado en el área de ensayo (índice). Por lo tanto, para comprobar sólo los archivos que no se quitaron

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

que tendrá que pasar por el aro adicionales para hacer frente a los nombres de archivo con espacios en cuando (opción -z a git diff y algunos de análisis más interesante)

+0

Gracias, es un buen comienzo.Sin embargo, si cambio un archivo sin organizarlo, aún se muestra. Estoy ejecutando git versión 1.7.0.1.147.g6d84b (compilación personalizada reciente). No estoy seguro si este es el comportamiento previsto. – igorw

+0

Eso suena extraño. El modificador "--cached" debería hacer que solo muestre los archivos que se han escenificado: aunque estoy probando esto con 1.6.5, parece sorprendente que eso haya cambiado ... ¿"git diff --cached" en su propio espectáculo los cambios sin escenario? – araqnid

+0

Después de algunas depuraciones, pude rastrearlo por otra causa. ¡Muchas gracias! – igorw

70

Una forma un poco más ordenado de la obtención de la misma lista es:

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

Esto devolverá la lista de archivos que necesitan ser comprobados.

Pero ejecutar php -l en su copia de trabajo puede no ser lo correcto. Si está realizando una confirmación parcial, es decir, simplemente seleccionando un subconjunto de las diferencias entre su conjunto de trabajo actual y el HEAD para la confirmación, la prueba se ejecutará en su conjunto de trabajo, pero certificará una confirmación que nunca ha existido en su disco.

Para hacerlo bien, debe extraer toda la imagen por etapas a un área de temperatura y realizar la prueba allí.

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 

Consulte Building a better pre-commit hook for Git para otra implementación.

+4

En realidad es posible canalizar el contenido del archivo a 'php -l'. Y eso es con lo que terminamos. Consulte aquí: http://github.com/phpbb/phpbb3/blob/develop-olympus/git-tools/hooks/pre-commit – igorw

+2

Para verificar la sintaxis de un archivo en etapas, puede usar 'git show: FILENAME | php -l'. –

7

Esto es lo que uso para mis cheques de 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 

para PHP que se verá así:

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

Bastante bien, pero no funciona para archivos parcialmente en etapas, porque lee todo el archivo. – igorw

0

git diff --cached no es suficiente si se ha especificado la llamada comprometerse con la bandera -a, y no hay manera de determinar si esa bandera ha sido arrojada al anzuelo. Ayudaría si los argumentos para comprometer deberían estar disponibles para el gancho para su examen.

+0

git diff --cached DOES parece ser suficiente. Sin embargo, creo que si se ejecuta estado git --porcelain de su gancho, todos los archivos que serán procesados ​​no tendrá un espacio en blanco o una? en la primera posición de la salida. No lo he probado completamente, pero hasta ahora, se ha mantenido en todas las condiciones que tengo en mi repositorio, una mezcla de archivos nuevos, agregados y modificados donde trato de enviar archivos explícitos, el conjunto predeterminado de archivos, - a por todo. ¿Por qué usar el estado de git en lugar de git diff? Creo que es más fácil de analizar. – mpersico

+0

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

+0

'git status --porcelain | perl -ane 'imprime $ F [1], qq (\ n) si m/^ [ACM] /' ' es una mejor respuesta. Tiene la ventaja de usar una opción --porcelain, garantizada para nunca cambiar. Usa tu propio analizador si perl es demasiado pesado para ti. – mpersico

7

Ninguna de las respuestas aquí admite nombres de archivos con espacios. La mejor manera para que se va a agregar la opción -z en combinación con xargs -0

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

Esto es lo que se da por git incorporada en las muestras (ver .git/ganchos/pre-commit.sample)

Cuestiones relacionadas