¿Qué son git hooks?
Como se habrán dado cuenta a lo largo de toda esta serie, git tiene una innumerable cantidad de funciones. Los “hooks” o ganchos son otras de estas tantas funciones extremadamente útiles pero poco utilizadas por muchos de nosotros. Los “hooks” son un conjunto de acciones que se ejecutan antes o después de un comando particular de git, es decir, si estamos utilizando un “pre-commit hook” se ejecutará una acción antes de realizar el “commit”, si dicha acción realizada antes del “commit” tiene una respuesta negativa podemos cancelar el “commit”, arrojar un error y viceversa. Podemos decir que los “hooks” son una capa extra que nos ayudan a no pasar por alto ciertos detalles.
Tipos de hooks
Existen una gran cantidad de “hooks” disponibles para aplicar, haremos un pequeño resumen de cada uno:
- applypatch-msg: ayuda a formatear un mensaje para cumplir un estándar deseado del proyecto (si existe). También puede ser utilizado para rechazar un “commit” después de inspeccionar el mensaje. Si se encuentra activado el “hook” commit-msg, applypatch-msg lo invoca.
- pre-applypatch: es usado para inspeccionar la rama donde se está trabajando y no permite un “commit” si el mismo no pasa unas pruebas. Si se encuentra activado pre-commit “hook” lo invoca.
- post-applypatch: es usado principalmente para notificaciones (escribe un mensaje que se desee por la consola).
- pre-commit: es invocado por
git commit
, la utilidad por defecto de este “hook” es atrapar espacios en blanco al final de cada línea y abortar el “commit” si esto llega a ocurrir. Pero se puede agregar cualquier cantidad de pruebas a este “hook” para asegurar que nuestros “commits” se encuentran como queremos que estén. Se puede ignorar este “hook” utilizando la bandera--no-verfy
al final del “commit”. - prepare-commit-msg: el propósito de este “hook” es preparar el comentario con un formato por defecto que uno desee que tenga (si existe). Un ejemplo de un comportamiento similar de este “hook” es cuando generamos un merge de una rama y git nos genera de manera automática un comentario referente al merge.
- commit-msg: funciona de la misma manera que applypatch-msg. Podemos ignorarlo haciendo uso de la bandera
--no-verfy
. - post-commit: funciona de la misma manera que post-applypatch (imprime un mensaje de notificación) pero actúa una vez que se realizó el “commit”.
- pre-rebase: éste gancho es activado por el comando
git rebase
y puede ser usado para prevenir que una rama sea rebasada. - post-checkout: éste gancho se activa cuando se utiliza
git checkout
y puede ser usado para mostrar las diferencias entre las diferentes ramas o setear alguna metadata necesaria. - post-merge: es invocado por el comando
git merge
y puede ser usado para salvar o restablecer cualquier metadata asociada con una rama de trabajo. - pre-receive: este gancho es invocado por
git-receive-pack
en el repositorio remoto, y ocurre cuando se realiza ungit push
. Es el encargado de actualizar las referencias de los objetos y el estado del update (actualización). - update: de la misma manera que el pre-receive se invoca con
git-receive-pack
y ocurre con el comandogit-push
. Este gancho actualiza las referencias del repositorio remoto y puede ser utilizado para prevenir ungit push -f
(forzado). - post-receive: es ejecutado por
git-receive-pack
y ocurre cuando utilizamos el comandogit push
. A diferencia de los otro dos update y pre-receive actúa del lado del servidor. Se puede utilizar este gancho para enviar emails después de realizar el “commit” o verificar cualquier información de relevancia. - post-rewrite: es invocado por los comandos que reescriben commits tales como
git commit --amend
ogit rebase
.
Esta información fue tomada de kernel.org.
¿Cómo se usan los hooks?
Para poder utilizar algún “hook” debemos crearlos manualmente. La mayoría de los “hooks” son scripts de “shell”, aunque podemos utilizar otros lenguajes de “scripting” si queremos. Absolutamente todos los “hooks” que necesitemos o creemos deben estar en la carpeta .git/hooks/
dentro del repositorio de git de nuestro interés. Por defecto todos los proyectos de git se crean con “hooks” pero hay que renombrarlos correctamente para que funcionen.
Hagamos una pequeña demostración de como se usan:
Entremos primero en la carpeta para observar cuales son los ganchos que por defecto que vienen con la creación del repositorio git.
$ cd .git/hooks $ ls -la total 40 drwxr-xr-x 11 albertogg 374 Sep 18 14:27 . drwxr-xr-x 15 albertogg 510 Sep 18 14:27 .. -rwxr-xr-x 1 albertogg 452 Jun 26 23:08 applypatch-msg.sample -rwxr-xr-x 1 albertogg 896 Jun 26 23:08 commit-msg.sample -rwxr-xr-x 1 albertogg 189 Jun 26 23:08 post-update.sample -rwxr-xr-x 1 albertogg 398 Jun 26 23:08 pre-applypatch.sample -rwxr-xr-x 1 albertogg 640 Sep 18 14:27 pre-commit -rw-r--r-- 1 albertogg 1348 Jun 26 23:08 pre-push.sample -rwxr-xr-x 1 albertogg 4951 Jun 26 23:08 pre-rebase.sample -rwxr-xr-x 1 albertogg 1239 Jun 26 23:08 prepare-commit-msg.sample -rwxr-xr-x 1 albertogg 3611 Jun 26 23:08 update.sample
1234567891011121314 $cdgit/hooks$ls-latotal40drwxr-xr-x11albertogg 374Sep1814:27drwxr-xr-x15albertogg 510Sep1814:27-rwxr-xr-x 1albertogg 452Jun2623:08applypatch-msgsample-rwxr-xr-x 1albertogg 896Jun2623:08commit-msgsample-rwxr-xr-x 1albertogg 189Jun2623:08post-updatesample-rwxr-xr-x 1albertogg 398Jun2623:08pre-applypatchsample-rwxr-xr-x 1albertogg 640Sep1814:27pre-commit-rw-r--r-- 1albertogg1348Jun2623:08pre-pushsample-rwxr-xr-x 1albertogg4951Jun2623:08pre-rebasesample-rwxr-xr-x 1albertogg1239Jun2623:08prepare-commit-msgsample-rwxr-xr-x 1albertogg3611Jun2623:08updatesample
Vamos a utilizar en este caso el “pre-commit hook”. Debemos renombrar los archivos y quitarles la terminación “.sample” para que git los reconozca normalmente.
$ mv pre-commit.sample pre-commit
1 $mv pre-commitsample pre-commit
Ahora voy a agregar unos espacios en blanco a cualquier línea dentro de uno de los archivos del repositorio y luego a intentar realizar un “commit” para que observen lo que sucede.
$ nano Archivo2_cambio_de_nombre.txt # agrego unos espacios en blanco al final de la segunda línea. # intento realizar un "commit" y esto es lo que ocurre. $ git commit -am "Prueba de hook" Archivo2_cambio_de_nombre.txt:2: trailing whitespace. +Agregando una segunda linea
1234567 $nano Archivo2_cambio_de_nombretxt# agrego unos espacios en blanco al final de la segunda línea. # intento realizar un "commit" y esto es lo que ocurre. $git commit-am"Prueba de hook"Archivo2_cambio_de_nombretxt:2:trailing whitespace+Agregando una segunda linea
Se canceló el “commit” ya que no pasó la prueba que realiza el “pre-commit hook”. A partir de este momento debemos corregir y volver a realizar el “commit” para observar si hemos solventado todos los problemas existentes, de ser así se realizará el “commit” normalmente y sin espacios en blanco.
¿Quién utiliza git hooks?
Si han llegado a utilizar servicios como heroku.com muy seguramente se habrán dado cuenta que cada vez que uno realiza un git push
hacia el repositorio git de heroku, el mismo utiliza varios “hooks” para detectar que tipo de proyecto es (lenguaje, framework, estructura de carpetas) y de esa manera buscar el buildpack adecuado para nuestro proyecto y así descargarse las librerías adecuadas y construir el proyecto en el servidor. Si alguna vez han subido un proyecto que heroku no reconoce también se habrán dado cuenta que el “hook” no permite la actualización y subida de las referencias del proyecto al servidor, cancelando el push.
Conclusión
En este último capítulo y en conjunto con los cursos anteriores hemos adquirido el conocimiento necesario para poder entender que son estos “hooks” y para que nos pueden ayudar en un proyecto. Capaz cuando leas el contenido de este curso no pienses que necesitas “hooks”, pero en un proyecto donde trabajan muchas personas es muy probaba que podamos prevenir comportamientos no deseados si los usamos. Si te surge algún tipo de duda no te detengas y déjanos un comentario, que gustosamente lo responderemos.
¡Hasta la semana entrante!