3 trucos para automatizar tus tareas de desarrollo con git hooks

01/08/2018Artículo original

El sistema de control de versiones Git, como muchos otros, viene con unos cuantos trucos en la manga que lo hacen muy extensible de forma programática. En este artículo aprenderemos uno de ellos, los hooks, que permiten realizar acciones automáticas junto a muchos de los comandos típicos de Git.

Los hooks son programas que se ejecutan antes o después que algún evento importante de Git. Por ejemplo, antes de completar un git commit, tras cambiar de rama o antes de enviar los cambios durante un git push. Se almacenan en el directorio .git/hooks/ de cada proyecto clonado, y es necesario que sean programas o scripts ejecutables (en sistemas tipo Unix han de tener el permiso de ejecución).

Para añadir un hook a tu proyecto, simplemente copia o enlaza a dicho directorio el programa que quieras ejecutar automáticamente con el nombre del “evento” (por ejemplo, pre-commit, todos los posibles nombres están disponibles en la documentación de Git). Si el programa es un script y quieres que el resto de colaboradores puedan usarlo, es conveniente incluirlo en la raíz del proyecto y crear un acceso directo a él en .git/hooks/:

ln -s ../../pre-commit.sh .git/hooks/pre-commit

Vamos a ver algunas aplicaciones practicas de los hooks de Git.

1. Comprobar la calidad del código antes del commit

Los hooks que se ejecutan previos a la confirmación de un commit son útiles puesto que nos permiten realizar comprobaciones sobre el código añadido o eliminado justo antes de reflejar dichos cambios en el árbol de versiones del repositorio. Si el hook falla o devuelve código de error, el commit no se efectuará.

  Python sobrepasa a Java como lenguaje de programación más popular por primera vez en los 20 años del indice TIOBE

En el siguiente ejemplo (válido para sistemas Unix, como Linux o macOS), utilizamos el paquete jslint de Node.js para comprobar la calidad del código de una aplicación JavaScript antes de completar el commit:

#!/bin/bash# pre-commit.sh# Guardar los cambios no confirmadosSTASH_NAME="pre-commit-$(date +%s)"git stash save -q --keep-index $STASH_NAME# Comprobaciones y testsjslint my_application.js || exit 1# Recuperar los cambios guardadosSTASHES=$(git stash list)if [[ $STASHES == "$STASH_NAME" ]]; then git stash pop -qfi

Se podría proceder con la misma estrategia a lanzar una suite de tests sobre la aplicación u otras comprobaciones necesarias, por ejemplo, una búsqueda de claves o tokens secretos para evitar introducirlos al repositorio.

2. Generar la documentación conforme se suben cambios

Si en nuestro proyecto contamos con un generador de documentación a partir del código, podemos ejecutarlo regularmente conforme desarrollamos mediante un hook de tipo pre-push. Simplemente lanzamos el comando necesario para componer toda la documentación en algún directorio (por ejemplo, docs/) y la añadimos a un nuevo commit.

En el siguiente listado te muestro varios ejemplos de los posibles comandos que podrías usar para tal fin:

#!/bin/bash# pre-push.sh# Genera la documentacióndoxygen Doxyfile# Otro ejemplo, con Python:pydoc3 -w docs/# Otro ejemplo, con R:Rscript -e 'pkgdown::build_site()'# Añade y confirma los cambios relativos a la documentacióngit add docs/git commit -m "Update documentation ($(date +%F@%R))"

La ventaja de esto es que, si utilizas GitHub Pages o un servicio similar para servir tu documentación online, siempre estará al día con los cambios de tu código y no se quedará obsoleta.

  Programación Android: Interfaz gráfica

3. Comprueba dependencias al cambiar de rama

Por último, una aplicación de los hooks muy interesante es actualizar las dependencias instaladas al cambiar de rama en un proyecto. Si utilizas gestores de paquetes y dependencias para tu lenguaje de desarrollo (Pip en Python, npm en Node.js, Nuget en .NET, Bundler en Ruby, Cargo en Rust…), te puede ser muy útil el siguiente ejemplo.

El listado de código a continuación correspondería a un hookpost-checkout, y lo que consigue es comprobar si entre la rama anterior y la nueva ha cambiado el archivo de dependencias (en este caso, Gemfile para Ruby), en cuyo caso ejecuta el instalador conveniente (en este caso, bundle).

#!/bin/bash# post-checkout.shif [ $1 = 0000000000000000000000000000000000000000 ]; then # Si estamos en un proyecto recién clonado, comparar con el directorio vacío old=$(git hash-object -t tree /dev/null)else # El primer argumento es el hash de la anterior HEAD old=$1fiif [ -f Gemfile ] && git diff --name-only $old $2 | egrep -q '^Gemfile|\.gemspec$'then # Vaciar $GIT_DIR evita problemas si bundle llama a git (unset GIT_DIR; exec bundle) # Se completa el checkout aunque falle bundler truefi

Puedes adaptar este código para tu propio uso simplemente cambiando Gemfile por el archivo de dependencias que utilices (package.json o requirements.txt, por ejemplo) y bundle por el comando correspondiente (npm install o pip install -r requirements.txt, por ejemplo).

  Aprende como un atleta

Fuentes y más información:

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Contiene enlaces a sitios web de terceros con políticas de privacidad ajenas que podrás aceptar o no cuando accedas a ellos. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad