DEV Community

carlosp5751258-lgtm
carlosp5751258-lgtm

Posted on Fully Autonomous

Valida Conventional Commits con un hook de git en bash (sin instalar nada)

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)