W3docs

Git hooks

Aprende Git hooks — scripts que se ejecutan automáticamente en el ciclo de vida de Git para hacer lint, pruebas y validaciones. Incluye un ejemplo pre-commit.

¿Qué son los Git hooks?

Los Git hooks son scripts que Git ejecuta automáticamente cuando ocurren ciertos eventos: hacer un commit, fusionar ramas, hacer push y más. Permiten agregar acciones personalizadas al ciclo de vida de Git: ejecutar un linter antes de cada commit, validar el formato de un mensaje de commit o bloquear un push si las pruebas fallan. Los hooks son la forma en que los equipos aplican controles de calidad localmente, antes de que el código defectuoso salga de la máquina.

Esta página cubre dónde viven los hooks, la diferencia entre hooks del lado del cliente y del servidor, los hooks más útiles con ejemplos funcionales, cómo un hook aborta una operación, cómo omitir un hook y cómo compartir hooks en un equipo.

Git hooks disparándose en las etapas del ciclo de vida de commit y push

Dónde viven los hooks

Cada repositorio tiene un directorio .git/hooks que contiene scripts de ejemplo con el sufijo .sample. Para activar un hook, añade un script ejecutable con el nombre exacto del hook y sin extensión:

ls .git/hooks
# pre-commit.sample  commit-msg.sample  pre-push.sample ...

Elimina el sufijo .sample (o crea el archivo desde cero) y hazlo ejecutable:

chmod +x .git/hooks/pre-commit

Un hook puede escribirse en cualquier lenguaje, siempre que el archivo sea ejecutable y comience con una línea shebang adecuada (#!/bin/sh, #!/usr/bin/env python3, #!/usr/bin/env node, etc.). Git solo requiere que el archivo tenga exactamente el nombre de un hook conocido, sea ejecutable y devuelva un código de salida.

Hooks del lado del cliente vs. del servidor

  • Los hooks del lado del cliente se ejecutan en tu máquina alrededor de operaciones locales como hacer commits y push. Son ideales para hacer lint y pruebas.
  • Los hooks del lado del servidor (como pre-receive y post-receive) se ejecutan en el repositorio remoto cuando recibe un push — útiles para aplicar políticas de forma centralizada.

Los hooks más utilizados son del lado del cliente:

HookSe disparaUso típico
pre-commitAntes de crear un commitHacer lint y probar archivos en staging; abortar ante fallos.
prepare-commit-msgAntes de que se abra el editor de mensajesInsertar una plantilla o número de ticket.
commit-msgDespués de escribir el mensajeAplicar una convención de mensajes.
post-commitDespués de completar un commitEnviar una notificación; no afecta el commit.
pre-pushAntes de enviar un pushEjecutar la suite de pruebas completa como última verificación.

Cómo un hook aborta una operación

Todo el mecanismo de control es el código de salida. Para un hook "pre-" (pre-commit, pre-push, commit-msg, …):

  • Salida 0 → el hook aprobó la operación y Git continúa.
  • Salida distinta de cero → Git cancela la operación. El commit no se crea o el push no se envía.

Los hooks "post-" (post-commit, post-merge, …) se ejecutan después de que la acción ya se completó, por lo que su código de salida es ignorado — no pueden deshacer nada. Úsalos para notificaciones, no para validación.

Un ejemplo de pre-commit

Este hook pre-commit ejecuta el linter del proyecto y bloquea el commit si reporta problemas. Como sh aborta ante el comando fallido gracias a set -e, no se necesita ninguna comprobación extra de $?:

#!/bin/sh
set -e
echo "Running lint..."
npm run lint

Si npm run lint sale con código distinto de cero, set -e propaga ese código y el commit se aborta. Si prefieres un mensaje personalizado, comprueba el resultado explícitamente:

#!/bin/sh
if ! npm run lint; then
  echo "Lint failed — commit aborted. Fix the issues and try again."
  exit 1
fi

Guarda esto como .git/hooks/pre-commit y ejecuta chmod +x .git/hooks/pre-commit.

Un ejemplo de commit-msg

El hook commit-msg recibe un argumento: la ruta a un archivo temporal que contiene el mensaje propuesto. Lee ese archivo, valídalo y sal con código distinto de cero para rechazarlo. Este ejemplo aplica un prefijo de estilo Conventional Commits:

#!/bin/sh
# $1 is the path to the file containing the commit message
message=$(head -n1 "$1")
pattern='^(feat|fix|docs|style|refactor|test|chore): .+'

if ! echo "$message" | grep -Eq "$pattern"; then
  echo "Commit message must start with feat:, fix:, docs:, etc."
  exit 1
fi

Omitir un hook

Un hook es una red de seguridad, no una barrera. Cuando genuinamente necesites saltarte los hooks pre-commit y commit-msg para una operación, usa --no-verify:

git commit --no-verify -m "WIP: skip checks"
git push --no-verify

Úsalo con moderación — saltarse el linter es cómo el código defectuoso se cuela en el historial.

Compartir hooks con un equipo

Como .git/hooks no se incluye en los commits, los hooks no viajan con un clon. Los equipos resuelven esto almacenando los hooks en un directorio rastreado y apuntando Git hacia él:

git config core.hooksPath .githooks

Ahora Git busca en el directorio rastreado .githooks/ en lugar de .git/hooks. Haz commit de tus scripts allí, márcalos como ejecutables, y cada miembro del equipo los obtendrá después de ejecutar el mismo comando git config (o después de que un script de configuración lo haga por ellos). Consulta Git config para más información sobre cómo almacenar configuraciones por repositorio.

Herramientas como Husky automatizan exactamente esto para proyectos JavaScript, configurando hooks compartidos durante la instalación. Para políticas que no puedes permitir que nadie omita con --no-verify, aplícalas con hooks del lado del servidor o con la protección de ramas de tu plataforma de alojamiento, ya que los hooks del lado del cliente siempre residen en la máquina del desarrollador.

Temas relacionados

  • git commit — el comando alrededor del cual se envuelven los hooks pre-commit y commit-msg.
  • Firmar commits — verificar la autoría, a menudo combinado con hooks.
  • Git config — donde se almacenan core.hooksPath y otras configuraciones.
  • Git alias — atajos para los comandos que ejecutan tus hooks.

Práctica

Práctica
¿Qué afirmaciones sobre los Git hooks son correctas?
¿Qué afirmaciones sobre los Git hooks son correctas?
Was this page helpful?