Un commit útil no cuenta todo lo que hiciste: conserva la decisión que el historial necesita

Pregunta de investigación: cuando alguien abre el historial de un proyecto dentro de tres meses, ¿puede entender qué decisión tomó cada commit o solo descubre una secuencia de verbos como “cambia”, “actualiza” y “arregla”?

Un mensaje de commit no es un recibo para demostrar que trabajaste. Es una pequeña pieza de documentación que viaja con el código, aparece en el historial, puede alimentar un changelog y ayuda a decidir si un cambio se puede revertir sin romper otra cosa. Esa función es más exigente que escribir una frase gramaticalmente correcta.

La propia documentación de git commit recomienda una primera línea corta que resuma el cambio y deja el cuerpo para explicar detalles. La especificación de Conventional Commits añade tipos, alcance, cuerpo y pies de mensaje para hacer explícita la intención y facilitar herramientas automáticas. Ninguna de estas reglas convierte un mensaje mediocre en una buena decisión, pero ambas dejan claro que el historial tiene lectores y usos futuros.

Primera pista: describir la actividad no es explicar el cambio

Compara dos mensajes para el mismo cambio:

MensajeQué permite saberQué deja sin responder
actualiza loginAlguien modificó algo relacionado con el acceso.Qué comportamiento cambió, por qué era necesario y qué parte queda afectada.
fix(auth): rechaza tokens expirados antes de cargar el perfilEl cambio corrige una condición de autenticación y ocurre antes de una operación concreta.Los detalles de implementación y las razones de negocio, si son relevantes.

El segundo no es mejor porque tenga un prefijo de moda. Es mejor porque comprime una decisión verificable: hay un tipo de problema, un área del sistema y un momento específico del flujo. Si mañana aparece una regresión durante la carga del perfil, el historial ofrece una hipótesis que se puede investigar.

Esta diferencia responde a una pregunta que la lista original trataba de forma indirecta: ¿qué debe recordar el historial? No necesita guardar cada archivo tocado ni cada comando ejecutado. Necesita conservar el motivo y el efecto que permitan interpretar el diff. La actividad pertenece a la herramienta; la decisión pertenece a la memoria del proyecto.

El título del commit debe funcionar como un índice

La primera línea es lo que se ve cuando alguien ejecuta git log --oneline, revisa una rama o busca cuándo se introdujo un comportamiento. Por eso debe ser breve sin volverse vacío. “Corrige errores” ocupa pocos caracteres, pero no ayuda a buscar nada. “Evita duplicar el envío del formulario” es más largo y mucho más útil.

Una fórmula práctica es escribir la línea como una respuesta a la pregunta “¿qué comportamiento cambió?”. No empieces por el archivo: modifica app.js describe el lugar, no el efecto. Prueba con un verbo en imperativo y un objeto concreto:

fix: evita enviar dos veces el formulario
feat(search): conserva la consulta al volver atrás
docs(api): aclara el formato de la respuesta de usuarios

El imperativo no es una superstición. Mantiene una convención consistente con la forma en que Git presenta un commit como una instrucción aplicada al proyecto. Sin embargo, la consistencia no debe ganarle a la precisión. “Actualiza estilos” en imperativo sigue siendo pobre si el lector no puede distinguir qué se actualizó.

El límite de caracteres tampoco es una ley de la naturaleza. El objetivo de una primera línea corta es que funcione como índice en vistas compactas. Cuando una explicación necesita más contexto, no debes comprimir cinco decisiones dentro de un título interminable: usa el cuerpo.

El cuerpo explica la decisión que el diff no puede explicar

Un diff muestra líneas añadidas y eliminadas, pero no siempre muestra la razón de una elección. Si cambias un timeout de cinco a treinta segundos, el diff revela el número, no el incidente que lo motivó, la condición de red que se observó o el riesgo que aceptaste. El cuerpo de un commit es el lugar para ese contexto.

Un buen cuerpo responde, cuando sea necesario, a tres preguntas:

  1. Qué situación provocó el cambio. Por ejemplo, una API lenta que agotaba la espera del cliente.
  2. Qué decisión se tomó y por qué. Tal vez se aumentó el timeout solo para una operación concreta en lugar de cambiar el valor global.
  3. Qué límite o consecuencia queda. Un proceso más largo puede necesitar cancelación, reintentos o una métrica adicional.

No todos los commits necesitan un ensayo. Una corrección obvia y local puede vivir en una sola línea. Pero si el lector futuro tendría que abrir varios issues, buscar una conversación antigua o preguntar al autor para entender el motivo, el cuerpo probablemente ahorra trabajo. La pregunta no es “¿puedo escribir más?”, sino “¿qué información no está en el diff?”.

Por ejemplo:

fix(upload): evita reintentar archivos rechazados por tamaño

El cliente volvía a enviar el mismo archivo cuando la API respondía 413.
Ahora el límite se muestra al usuario y el reintento queda reservado para
fallos temporales de red.

La explicación no repite línea por línea el código. Conserva una distinción de comportamiento que podría desaparecer durante una futura refactorización.

Atomicidad: la calidad del mensaje depende también del tamaño de la decisión

Decir que un commit debe ser “atómico” suele sonar a regla abstracta. En realidad significa que el conjunto de cambios debe representar una unidad lógica que pueda revisarse, probarse o revertirse como una sola decisión. Si mezclas un cambio de validación, una actualización de dependencias y un formateo de todo el proyecto, el mensaje tendrá que ser general porque el commit ya contiene demasiadas historias.

SituaciónProblema del commit mezcladoSeparación preferible
Se corrige una validación y se reordenan todos los imports.El diff de la validación queda enterrado entre ruido de formato.Un commit para la corrección y otro para el estilo, si ambos son necesarios.
Se añade una función y se cambia una migración de base de datos.Revertir la función puede dejar la migración en un estado ambiguo.Separar cambios coordinados o documentar claramente su dependencia.
Se actualiza una dependencia y se corrigen errores no relacionados.No sabes si una regresión viene de la versión nueva o del código corregido.Actualizar la dependencia en un commit y corregir cada problema con contexto propio.

La especificación de Conventional Commits incluso recomienda volver a varios commits cuando una modificación corresponde a más de un tipo. La idea no es ralentizar toda iteración: es impedir que la velocidad de hoy convierta el historial en una pared de mensajes indistinguibles mañana.

Hay una excepción práctica. A veces una migración, un cambio de código y una prueba forman una única unidad inseparable. En ese caso, la solución no es dividir artificialmente el trabajo; es escribir un mensaje que explique la relación entre las piezas. Atomicidad no significa “un archivo por commit”, sino “una decisión coherente por commit”.

Conventional Commits es un contrato útil, no un sustituto del criterio

Los prefijos feat, fix, docs, refactor o test hacen que la intención sea visible y permiten automatizar changelogs o versiones. También pueden ayudar a una persona que filtra el historial. Pero escribir fix: delante de una frase vaga no crea información que no estaba allí.

Usa un scope cuando reduce la ambigüedad:

feat(checkout): permite guardar una dirección secundaria
fix(cache): invalida la lista tras eliminar un producto
refactor(parser): separa tokens de operadores

No lo uses como decoración si todos los commits dicen feat(core) sin que “core” permita localizar un área real. Tampoco conviertas la especificación en una taxonomía rígida que obligue a clasificar un cambio ambiguo de forma falsa. El propio estándar permite tipos adicionales y scopes opcionales; su propósito es comunicar la naturaleza del cambio, no ganar una competición de formatos.

Un proyecto individual puede empezar con tres categorías. Un equipo con despliegues automáticos puede necesitar una convención más precisa. La decisión correcta depende de qué herramientas y lectores existen, no de copiar la configuración de un repositorio popular.

Un mensaje publicado no es texto descartable

Es tentador corregir una frase después de hacer push como si editaras una nota local. Pero cambiar el mensaje crea un nuevo ID de commit. La guía de GitHub sobre cambiar mensajes de commit advierte que, si el commit ya fue publicado, reescribir el historial puede exigir un force push y afectar a colaboradores que basaron trabajo en la versión anterior.

La consecuencia no es “nunca corrijas un mensaje”. Antes de publicar, revisa la línea y el cuerpo igual que revisas el código. Después de publicar, pregunta quién más usa esa historia y si el beneficio de corregir la descripción supera el coste de reescribirla. Si el mensaje contiene información sensible, cambiarlo tampoco garantiza que desaparezca de todas las copias o referencias remotas.

Este detalle cambia la forma de pensar un commit: no es solo el texto que acompaña a una acción, sino una parte identificable de la historia. La precisión temprana es más barata que una limpieza posterior.

Un pequeño experimento para mejorar tus propios mensajes

Abre un repositorio personal y revisa los últimos veinte commits. No los evalúes por ortografía. Intenta responder a estas preguntas sin abrir cada diff:

PreguntaSi la respuesta es “no”Qué hábito probar
¿Puedo localizar el área afectada?El título usa palabras como “cambios” o “mejoras”.Añadir un objeto concreto o un scope útil.
¿Entiendo el efecto visible?El mensaje solo nombra archivos.Escribir el comportamiento que cambió.
¿Sé por qué el cambio era necesario?El diff muestra qué, pero no el motivo.Añadir un cuerpo breve con contexto.
¿El commit puede revisarse como una unidad?El mensaje necesita “y también”.Separar decisiones o explicar su dependencia.

Después, elige un solo hábito para los próximos cinco commits: quizá reemplazar “actualiza” por un verbo que describa el efecto, o separar commits que mezclan código y formato. Medir una mejora pequeña produce un historial más coherente que memorizar diez reglas y olvidarlas al día siguiente.

Si estás aprendiendo el flujo completo, revisa también la guía de comandos básicos de Git, la explicación de extensiones de VS Code y el artículo sobre automatizar tareas repetitivas. El mensaje tiene más valor cuando encaja en un proceso que realmente revisa, prueba y publica cambios.

Lo que debería quedar claro al leer tu historial

Un historial útil no cuenta una autobiografía del programador. Cuenta las decisiones que cambiaron el comportamiento del sistema. La primera línea permite escanear; el cuerpo conserva el contexto que el diff no puede mostrar; la atomicidad limita la cantidad de historias que cada commit intenta contar; y una convención como Conventional Commits vuelve esas intenciones más fáciles de procesar.

Antes de ejecutar git commit, lee el mensaje como si no supieras nada del cambio. Si solo responde “qué archivos toqué”, todavía falta la parte que más ayudará a tu futuro yo: qué problema resolví, qué comportamiento decidí y qué límite debo recordar.

Preguntas que suelen aparecer al escribir commits

¿Es obligatorio usar siempre el modo imperativo?

No es una obligación del lenguaje Git. Es una convención que ayuda a mantener una voz consistente y hace que las líneas del historial se lean como cambios aplicados. La precisión del mensaje importa más que repetir un verbo en imperativo sin explicar el efecto.

¿Debo limitar todos los títulos a cincuenta caracteres?

Una primera línea breve funciona bien como índice, pero el límite exacto depende del flujo del equipo. Si necesitas contexto adicional, usa el cuerpo en lugar de meter varias decisiones en una línea difícil de leer.

¿Cuándo conviene añadir un cuerpo al commit?

Cuando el diff no explica por qué se tomó la decisión, qué incidente motivó el cambio, qué riesgo se aceptó o qué relación existe entre varias piezas modificadas. Una corrección obvia y pequeña puede no necesitarlo.

¿Conventional Commits sirve para un proyecto personal?

Puede servir si quieres practicar una estructura, generar changelogs o buscar cambios con más facilidad, pero no es indispensable. Elige la convención por el problema que resuelve en tu proyecto y no por seguir una etiqueta popular.

¿Puedo cambiar un mensaje después de hacer push?

Técnicamente sí, pero cambiarlo crea otro ID de commit y puede requerir reescribir el historial remoto. Antes de hacerlo, considera a quienes ya descargaron la rama y si la corrección aporta suficiente valor para asumir ese coste.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio