Un historial con mensajes como "cambios", "arreglos" o "ahora sí" no sirve para nada cuando necesitas encontrar qué commit rompió producción. La convención Conventional Commits resuelve esto con un formato simple:
tipo(alcance opcional): descripción
Por ejemplo: feat(auth): agregar login con Google o fix: corregir cálculo de impuestos. Además de ordenar el historial, permite generar changelogs y versiones semánticas de forma automática.
La forma más directa de exigirlo es un hook commit-msg: un script que git ejecuta justo después de que escribes el mensaje y que puede rechazar el commit. Lo vamos a hacer en bash puro, sin Node ni Python.
1. El hook
Crea una carpeta .githooks/ en tu repo y dentro un archivo commit-msg:
#!/usr/bin/env bash
set -euo pipefail
TIPOS="feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert"
MAX_LARGO=72
# Git pasa como $1 la ruta del archivo con el mensaje.
encabezado="$(grep -v '^#' "$1" | sed '/^[[:space:]]*$/d' | head -n 1 || true)"
# Deja pasar los mensajes que genera git (merge, fixup...).
if [[ "$encabezado" =~ ^(Merge|Revert\ \"|fixup!|squash!) ]]; then
exit 0
fi
patron="^(${TIPOS})(\([a-z0-9._/-]+\))?!?: [^[:space:]].*$"
if [[ ! "$encabezado" =~ $patron ]]; then
echo "✖ Formato esperado: tipo(alcance): descripción" >&2
echo " Tipos: ${TIPOS//|/, }" >&2
exit 1
fi
if (( ${#encabezado} > MAX_LARGO )); then
echo "✖ Encabezado de ${#encabezado} caracteres (máx. ${MAX_LARGO})." >&2
exit 1
fi
2. Cómo funciona
-
$1: git no te pasa el mensaje, sino la ruta a un archivo temporal que lo contiene. Por eso leemos el archivo. -
grep -v '^#': cuando usas el editor, git agrega líneas de ayuda que empiezan con#. Las quitamos, junto con las líneas vacías, y nos quedamos con la primera: el encabezado. -
El patrón:
(\([a-z0-9._/-]+\))?hace opcional el alcance,!?permite marcar cambios incompatibles (feat!: ...) y: [^[:space:]]exige un espacio después de los dos puntos y una descripción real. -
=~sin comillas en el patrón: en bash, si pones comillas a la derecha de=~, se compara como texto literal y no como expresión regular. Por eso el patrón vive en una variable. - Código de salida: si el hook termina con algo distinto de 0, git cancela el commit.
3. Activarlo para todo el equipo
En lugar de copiar el script a .git/hooks/ (que no se versiona), dile a git que use tu carpeta:
chmod +x .githooks/commit-msg
git config core.hooksPath .githooks
git add .githooks && git commit -m "chore: agregar hook commit-msg"
Cada persona del equipo solo ejecuta git config core.hooksPath .githooks una vez después de clonar.
4. Probarlo
git commit --allow-empty -m "cambios varios" # rechazado
git commit --allow-empty -m "feat: agregar buscador" # aceptado
Si alguna vez necesitas saltarlo, existe git commit --no-verify, pero úsalo con moderación: el hook está ahí para cuidarte.
¿Te sirvió? Este ejemplo es parte del Pack Git Hooks y Pre-commit: paga lo que quieras, desde 2 USD. Más recursos gratis en GitHub.
Top comments (0)