- Conventional Commits intenta dar significado a los mensajes de commit con el formato
<type>[optional scope]: <description>, pero pone primero el tipo de cambio y deja el alcance como opcional, desplazando al final la información realmente necesaria para explorar el historial
- Quienes contribuyen, depuran o responden a incidentes buscan en el log de commits qué área de código fue tocada, y como los bugs pueden surgir en cualquier tipo de cambio, el scope es más importante que el tipo
- En casos como
fix(compiler): prevent namespaced SVG <style> elements from being stripped, la naturaleza de corrección de bug ya se entiende por la descripción, y en casos como refactor(core): Update webmcp support to use document.modelContext, un solo commit puede abarcar corrección, refactorización y nueva funcionalidad, por lo que el type es redundante y limitado
- La generación automática de CHANGELOG y la decisión de aumentar versiones semánticas fallan porque los lectores del log de commits y del changelog son distintos, y porque los reverts, las rupturas accidentales de compatibilidad y su resolución posterior pueden desalinear el resultado
- Los mensajes de commit con prefijo de scope muestran primero el sujeto del cambio, y también conviene basar las condiciones de build y despliegue en los archivos modificados vía
git diff, no en el tipo del título
Prioridades equivocadas
- Conventional Commits tiene como objetivo dar significado a los mensajes de commit para ayudar tanto a desarrolladores como a usuarios finales a entender los cambios
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
- La línea de título se compone de un
<type> como fix, feat, chore, docs, refactor, un scope opcional y una descripción
- Su defecto principal es que prioriza el tipo de cambio sobre el scope, que es el verdadero sujeto del cambio
- Hacer opcional el scope permite que falte la información más importante de un commit, y poner el type al inicio del título invierte las prioridades
Por qué el scope importa más que el type
- Quienes contribuyen leen el log de commits para encontrar cambios desde su última contribución, seguir el flujo general del proyecto y detectar commits que podrían entrar en conflicto con el trabajo en curso al hacer pull o rebase
- Quienes depuran buscan cambios que hayan tocado áreas relacionadas con el componente donde apareció el bug, y como un bug puede surgir en cualquier tipo de cambio, la información de type no ayuda
- Quienes responden a incidentes revisan el log alrededor del momento de la falla para ubicar el área que pudo causarla; si en el punto donde se disparan los errores del API de entrada aparece un commit con scope
auth, se vuelve un candidato fuerte
- Para quien lee el log de commits, lo importante no es qué clase de cambio fue, sino qué área tocó
La redundancia y las limitaciones del type
fix(compiler): prevent namespaced SVG <style> elements from being stripped ya deja claro por la descripción que se trata de una corrección de bug, así que el type fix es redundante
- El espacio en la línea de título de un commit es limitado, así que gastar caracteres en un type que ya puede inferirse de la descripción no aporta mucho
refactor(core): Update webmcp support to use document.modelContext actualiza la funcionalidad webmcp del componente core para soportar tanto document.modelContext como navigator.modelContext
- Ese cambio puede verse al mismo tiempo como corrección de bug, refactorización y nueva funcionalidad, pero la información realmente importante es que afecta al componente
core/webmcp
Los límites de la promesa de automatización
- La idea de generar automáticamente un CHANGELOG a partir de commits con herramientas como git-cliff o conventional-changelog tiene el problema de que el log de commits y el changelog tienen lectores distintos
- El CHANGELOG está dirigido a usuarios y se enfoca en entender las diferencias funcionales y de negocio entre versiones
- El log de commits está dirigido a desarrolladores y se enfoca en cómo cambia el codebase con el tiempo y en leer ese flujo desde la perspectiva del scope
- En proyectos de complejidad media o superior, una sola funcionalidad significativa suele entrar a través de varios commits; para el desarrollador, el proceso de implementación es útil, pero para el usuario final solo importa la nueva funcionalidad como resultado
- Los commits de revert son importantes para los desarrolladores dentro del flujo del historial, pero para el usuario final un cambio revertido equivale a un cambio que nunca existió
- Incrementar versiones semánticas según el type del commit puede llevar a subir la versión major aunque el cambio rompedor se haya revertido, a subir mal como minor o patch si la ruptura se detecta después, o a considerarlo rompedor aunque el problema desaparezca al combinarse con commits posteriores
- En estas situaciones se puede corregir el historial con rebase, pero el flujo de trabajo puede impedirlo o romperlo, y eso reduce la confiabilidad del flujo que transmite el log de commits
- Si los procesos de build o despliegue se activan por el type del título del commit, se pueden esquivar las herramientas automáticas con algo como un commit titulado
docs: fix typos que en realidad introduce una vulnerabilidad en el subsistema de autenticación
- Es mejor decidir las condiciones de build y despliegue identificando los archivos modificados con
git diff que basándose en el título del commit
Problemas de adopción y alternativa
- Conventional Commits propone que cada proyecto defina su propio conjunto de types, pero muchos proyectos simplemente adoptan los types por defecto de commitlint, que pueden no encajar bien con las características particulares de cada proyecto
- La especificación de Conventional Commits técnicamente solo define
fix y feat, y deja los demás types a criterio del proyecto
- En entornos corporativos, a veces los requisitos de gestión de cambios y auditoría obligan a incluir un número de ticket en cada mensaje de commit; si
<scope> se usa para ese ticket, se pierde metadata útil
- Linux, FreeBSD, Git, Go, NixOS y Node.js usan mensajes de commit con prefijo de scope adaptados a cada proyecto
- En el kernel de Linux, el subsystem; en el proyecto Go, la ruta del package; y en una arquitectura de microservicios, el nombre del microservicio, suelen ser scopes naturales
- scopedcommits.com plantea volver a un formato de mensajes de commit centrado en el scope y separar la generación del CHANGELOG de la gestión del log de commits
- Las ventajas de Conventional Commits no se tradujeron en beneficios reales, y su popularidad en proyectos open source, junto con la tendencia de la IA a elegirlo por defecto, ha propagado mensajes de commit con antipatrones mezclados
1 comentarios
Opiniones en Lobste.rs
Me da gusto ver un texto que ordena lógicamente la crítica a conventional commits en vez de quedarse en un rechazo instintivo.
Nunca me había detenido a pensar a fondo por qué no me gustaban, y supongo que fue porque empecé a asociarlos con el código generado por LLM. En particular, lo que más odio es
chore:; ojalá no volviéramos a inventar la notación húngara. Nunca debió haberse creadochore:ya ni siquiera existe en la guía de estilo de commits de Angular y, al parecer, al darse cuenta de lo ambiguo que era, lo absorbieron enbuild:Incluso cuando todavía estaba en el estilo de Angular, la descripción de
chore:proponía usos bastante específicos, pero en algunos proyectos de código abierto parece que se lo ponen por inercia a tareas que literalmente se sienten como algo fastidioso de hacerNo me encantan los conventional commits, pero creo que la alternativa propuesta pasa por alto por qué el scope es opcional
En proyectos pequeños que no tienen muchos módulos claramente definidos, el concepto de “scope” no resulta muy útil. Una práctica útil que ambos omiten es incluir números de issues o tickets en el título del commit; eso facilita entender el contexto adicional del cambio y ayuda especialmente durante la revisión de código. Eso sí, no me gusta volver obligatorio el número de ticket, porque termina generando tickets inútiles para cambios triviales, pero si un cambio resuelve un bug o una tarea específica, debería estar vinculado con ese bug o esa tarea
Sigue siendo mejor que un “type” de commit redundante que debería quedar claro con solo ver la línea de título
Si el cambio corresponde claramente a un ticket, se usa un commit con “número de ticket”; si no, se usa otra forma. Algunos cambios encajan bien con el type pero menos con el scope, y al revés, así que también se pueden mezclar scoped commits y conventional commits
Quiero decir: “no usen tipografía monoespaciada en el texto de los párrafos”
Aun así, en general estoy de acuerdo con la premisa del artículo
Aunque los mensajes de commit no sean muy buenos, para darse una idea del alcance de los cambios recomiendo usar seguido
git log --name-onlyogit log --statVer los nombres de archivos ayuda bastante a entender qué cambió sin tener que abrir cada commit uno por uno
La forma que de verdad me gusta es obligar el estilo de conventional commits en los títulos de PR
Los títulos de PR pueden ser editados por el maintainer incluso después de hacer merge, no hace falta reescribir el historial de commits y, junto con herramientas como release-drafter, se puede automatizar un changelog significativo en los releases de GitHub. Eso ofrece la granularidad adecuada para las partes interesadas que menciona el autor, es decir, separar funciones, correcciones y cambios incompatibles, y también manejar automáticamente una propuesta razonable de semver para el siguiente borrador de release en GitHub
El señalamiento del artículo de que componentes como
parse-libno deberían ser opcionales es correcto, y también coincido en que obligar conventional commits puede desalentar nuevas contribuciones. Pero las alternativas tampoco son claramente mejoresAun así, un identificador de cambio incompatible como
fix!(parse-lib): Don't leave sparse holes when parsing JSON arraystransmite bastante información. Es una corrección de bug en un componente específico, con un cambio incompatible que vino de forma inevitable junto con la corrección, e implica algo como un incremento menor de semver. Ese tipo de cosas se pueden poner en el título del PRAdmito que me obsesioné demasiado con conventional commits como forma de fomentar disciplina en los commits, y al final se volvió una costumbre
Ahora a veces me parece limitante y arbitrario. En algunos proyectos ni siquiera sé si esa es la convención real, y me fui acercando más al estilo Linux/Go/Node; en un monorepo con varias configuraciones, escribir
[service]: [what changed]se sentía más natural que forzar un type. De ahora en adelante quiero experimentar más con mi estilo personal de commits según lo que parezca útil, en vez de intentar encajar en una convención estricta, y los scoped commits se sienten como un buen punto de partidachore(lobsters): add my 2 cents on conventionals commits [JIRA-69420]Estoy de acuerdo con casi todo, pero discrepo en una cosa sobre la parte de “mostrarles a los colaboradores un registro revisionista que reduce la confiabilidad de la historia que cuenta el log de commits”. El autor parece estar hablando sobre todo de ramas públicas, y si son ramas públicas, me parece un consejo razonable. Pero no debería aplicarse a ramas privadas. Basta con dejarlo de forma que quien revise el cambio final —el maintainer o yo dentro de 10 años— pueda entenderlo; no hace falta conservar un hilo de pensamiento incoherente o, peor aún, un montón de commits tipo
address reviewLa respuesta a “¿por qué el scope es opcional?” es que, en proyectos pequeños, simplemente todo el proyecto es el scope
Coincido en que el “type” del commit no es tan útil, pero tampoco veo que haya una gran diferencia entre scoped commits y conventional commits. Los scoped son solo conventional sin “type”, y las distinciones entre fix, feat, refactor y chore tampoco están mal
Si todo el mundo está usando los valores predeterminados de commitlint tal cual, ¿no será más bien cuestión de hacer que la gente los use mejor?