Cómo escribir un mensaje de Git Commit

Contenido: Introducción | Las siete reglas | Consejos

Introducción: Por qué importan los buenos mensajes de commit

Si examinas el registro de cualquier repositorio Git al azar, probablemente encontrarás que sus mensajes de commit son más o menos un desastre. Por ejemplo, echa un vistazo a estas gemas de mis primeros días de commit en Spring:

$ git log --oneline -5 --author cbeams --before "Fri Mar 26 2009"e5f4b49 Re-adding ConfigurationPostProcessorTests after its brief removal in r814. @Ignore-ing the testCglibClassesAreLoadedJustInTimeForEnhancement() method as it turns out this was one of the culprits in the recent build breakage. The classloader hacking causes subtle downstream effects, breaking unrelated tests. The test method is still useful, but should only be run on a manual basis to ensure CGLIB is not prematurely classloaded, and should not be run as part of the automated build.2db0f12 fixed two build-breaking issues: + reverted ClassMetadataReadingVisitor to revision 794 + eliminated ConfigurationPostProcessorTests until further investigation determines why it causes downstream tests to fail (such as the seemingly unrelated ClassPathXmlApplicationContextTests)147709f Tweaks to package-info.java files22b25e0 Consolidated Util and MutableAnnotationUtils classes into existing AsmUtils7f96f57 polishing

Yikes. Compara esto con estos commits más recientes del mismo repositorio:

$ git log --oneline -5 --author pwebb --before "Sat Aug 30 2014"5ba3db6 Fix failing CompositePropertySourceTests84564a0 Rework @PropertySource early parsing logice142fd1 Add tests for ImportSelector meta-data887815f Update docbook dependency and generate epubac8326d Polish mockito usage

¿Qué prefieres leer?

El primero varía en longitud y forma; el segundo es conciso y consistente.
El primero es lo que ocurre por defecto; el segundo nunca ocurre por accidente.

Aunque los logs de muchos repositorios se parecen al primero, hay excepciones. El kernel de Linux y el propio Git son grandes ejemplos. Mira Spring Boot, o cualquier repositorio gestionado por Tim Pope.

Los colaboradores de estos repositorios saben que un mensaje de commit de Git bien elaborado es la mejor manera de comunicar el contexto sobre un cambio a los compañeros desarrolladores (y de hecho a sus futuros yo). Un diff te dirá lo que ha cambiado, pero sólo el mensaje de confirmación puede decirte correctamente por qué. Peter Hutterer hace este punto bien:

Reestablecer el contexto de una pieza de código es un desperdicio. No podemos evitarlo por completo, por lo que nuestros esfuerzos deben dirigirse a reducirlo en la medida de lo posible. Los mensajes de commit pueden hacer exactamente eso y como resultado, un mensaje de commit muestra si un desarrollador es un buen colaborador.

Si no has pensado mucho en lo que hace un gran mensaje de commit de Git, puede ser el caso de que no hayas pasado mucho tiempo usando git log y herramientas relacionadas. Hay un círculo vicioso aquí: debido a que el historial de commit es desestructurado e inconsistente, uno no pasa mucho tiempo usándolo o cuidándolo. Y debido a que no se utiliza o se cuida, sigue siendo desestructurado e inconsistente.

Pero un registro bien cuidado es una cosa hermosa y útil. git blame, revert, rebase, log, shortlog y otros subcomandos cobran vida. Revisar los commits y pull requests de otros se convierte en algo que vale la pena hacer, y de repente se puede hacer de forma independiente. Entender por qué algo ocurrió hace meses o años se convierte no sólo en posible sino en eficiente.

El éxito a largo plazo de un proyecto se basa (entre otras cosas) en su mantenibilidad, y un mantenedor tiene pocas herramientas más poderosas que el registro de su proyecto. Vale la pena tomarse el tiempo para aprender a cuidar uno adecuadamente. Lo que puede ser una molestia al principio pronto se convierte en un hábito, y eventualmente en una fuente de orgullo y productividad para todos los involucrados.

En este post, estoy abordando sólo el elemento más básico de mantener un historial de commit saludable: cómo escribir un mensaje de commit individual. Hay otras prácticas importantes como el aplastamiento de commits que no estoy tratando aquí. Tal vez voy a hacer eso en un post posterior.

La mayoría de los lenguajes de programación tienen convenciones bien establecidas en cuanto a lo que constituye el estilo idiomático, es decir, la nomenclatura, el formato y así sucesivamente. Hay variaciones en estas convenciones, por supuesto, pero la mayoría de los desarrolladores están de acuerdo en que la elección de uno y se adhieren a ella es mucho mejor que el caos que se produce cuando todo el mundo hace su propia cosa.

El enfoque de un equipo a su registro de confirmación no debe ser diferente. Para crear un historial de revisiones útil, los equipos deben acordar primero una convención de mensajes de confirmación que defina al menos las tres cosas siguientes:

Estilo. Sintaxis de marcado, márgenes de envoltura, gramática, mayúsculas, puntuación. Explique estas cosas, elimine las conjeturas y haga que todo sea lo más sencillo posible. El resultado final será una bitácora notablemente consistente que no sólo es un placer leer, sino que realmente se lee con regularidad.

Contenido. ¿Qué tipo de información debe contener el cuerpo del mensaje de confirmación (si lo hay)? ¿Qué no debería contener?

Metadatos. ¿Cómo deberían referenciarse los IDs de seguimiento de incidencias, números de pull request, etc.?

Afortunadamente, existen convenciones bien establecidas sobre lo que constituye un mensaje de confirmación de Git idiomático. De hecho, muchas de ellas se asumen en la forma en que funcionan ciertos comandos de Git. No hay nada que tengas que reinventar. Sólo tienes que seguir las siete reglas siguientes y estarás en camino de hacer commit como un profesional.

Las siete reglas de un gran mensaje de commit de Git

Tenlo en cuenta: Todo esto se ha dicho antes.

  1. Separa el asunto del cuerpo con una línea en blanco
  2. Limita la línea de asunto a 50 caracteres
  3. Capitaliza la línea de asunto
  4. No termines la línea de asunto con un punto
  5. Utiliza el modo imperativo en la línea de asunto
  6. Envuelve el cuerpo a 72 caracteres
  7. Utiliza el cuerpo para explicar qué y por qué vs. Cómo

Por ejemplo:

Summarize changes in around 50 characters or lessMore detailed explanatory text, if necessary. Wrap it to about 72characters or so. In some contexts, the first line is treated as thesubject of the commit and the rest of the text as the body. Theblank line separating the summary from the body is critical (unlessyou omit the body entirely); various tools like `log`, `shortlog`and `rebase` can get confused if you run the two together.Explain the problem that this commit is solving. Focus on why youare making this change as opposed to how (the code explains that).Are there side effects or other unintuitive consequences of thischange? Here's the place to explain them.Further paragraphs come after blank lines. - Bullet points are okay, too - Typically a hyphen or asterisk is used for the bullet, preceded by a single space, with blank lines in between, but conventions vary hereIf you use an issue tracker, put references to them at the bottom,like this:Resolves: #123See also: #456, #789

Separe el asunto del cuerpo con una línea en blanco

De la página de manual de git commit:

Aunque no es obligatorio, es una buena idea comenzar el mensaje de confirmación con una sola línea corta (menos de 50 caracteres) que resuma el cambio, seguida de una línea en blanco y luego una descripción más completa. El texto hasta la primera línea en blanco en un mensaje de confirmación se trata como el título de la confirmación, y ese título se utiliza en todo Git. Por ejemplo, Git-format-patch(1) convierte una confirmación en un correo electrónico, y utiliza el título en la línea de asunto y el resto de la confirmación en el cuerpo.

En primer lugar, no todas las confirmaciones requieren tanto un asunto como un cuerpo. A veces una sola línea está bien, especialmente cuando el cambio es tan simple que no es necesario más contexto. Por ejemplo:

Fix typo in introduction to user guide

No hace falta decir nada más; si el lector se pregunta cuál era la errata, puede simplemente echar un vistazo al propio cambio, es decir, utilizar git show o git diff o git log -p.

Si está confirmando algo como esto en la línea de comandos, es fácil usar la opción -m para git commit:

$ git commit -m"Fix typo in introduction to user guide"

Sin embargo, cuando una confirmación merece un poco de explicación y contexto, necesita escribir un cuerpo. Por ejemplo:

Derezz the master control programMCP turned out to be evil and had become intent on world domination.This commit throws Tron's disc into MCP (causing its deresolution)and turns it back into a chess game.

Los mensajes de confirmación con cuerpo no son tan fáciles de escribir con la opción -m. Es mejor escribir el mensaje en un editor de texto adecuado. Si aún no tienes un editor configurado para su uso con Git en la línea de comandos, lee esta sección de Pro Git.

En cualquier caso, la separación del asunto del cuerpo vale la pena cuando se examina el registro. Aquí está la entrada de registro completa:

$ git logcommit 42e769bdf4894310333942ffc5a15151222a87beAuthor: Kevin Flynn <[email protected]>Date: Fri Jan 01 00:00:00 1982 -0200 Derezz the master control program MCP turned out to be evil and had become intent on world domination. This commit throws Tron's disc into MCP (causing its deresolution) and turns it back into a chess game.

Y ahora git log --oneline, que imprime sólo la línea de asunto:

$ git log --oneline42e769 Derezz the master control program

O bien, git shortlog, que agrupa los commits por usuario, mostrando de nuevo sólo la línea de asunto para ser más concisos:

$ git shortlogKevin Flynn (1): Derezz the master control programAlan Bradley (1): Introduce security program "Tron"Ed Dillinger (3): Rename chess program to "MCP" Modify chess program Upgrade chess programWalter Gibbs (1): Introduce protoype chess program

Hay una serie de otros contextos en Git en los que la distinción entre la línea de asunto y el cuerpo entra en juego-pero ninguno de ellos funciona correctamente sin la línea en blanco en medio.

Limitar la línea de asunto a 50 caracteres

50 caracteres no es un límite estricto, sólo una regla general. Mantener las líneas de asunto en esta longitud asegura que son legibles, y obliga al autor a pensar por un momento en la forma más concisa de explicar lo que está pasando.

Consejo: Si usted está teniendo un tiempo difícil de resumir, puede ser que esté confirmando demasiados cambios a la vez. Esfuérzate por hacer commits atómicos (un tema para otro post).

La interfaz de usuario de GitHub es plenamente consciente de estas convenciones. Le advertirá si se pasa del límite de 50 caracteres:

Y truncará cualquier línea de asunto de más de 72 caracteres con una elipsis:

Así que intente alcanzar los 50 caracteres, pero considere 72 como el límite duro.

Capitalice la línea de asunto

Esto es tan simple como parece. Comience todas las líneas de asunto con una letra mayúscula.

Por ejemplo:

  • Acelere a 88 millas por hora

En lugar de:

  • acelere a 88 millas por hora

No termine la línea de asunto con un punto

La puntuación final es innecesaria en las líneas de asunto. Además, el espacio es precioso cuando se trata de mantenerlos en 50 caracteres o menos.

Ejemplo:

  • Abra las puertas de la bahía de la cápsula

En lugar de:

  • Abra las puertas de la bahía de la cápsula.

Utilice el modo imperativo en la línea de asunto

El modo imperativo sólo significa «hablado o escrito como si diera una orden o instrucción». Algunos ejemplos:

  • Limpia tu habitación
  • Cierra la puerta
  • Saca la basura

Cada una de las siete reglas que estás leyendo ahora mismo está escrita en imperativo («Envuelve el cuerpo a 72 caracteres», etc.).

El imperativo puede sonar un poco rudo; por eso no lo usamos a menudo. Pero es perfecto para las líneas de asunto de los commits de Git. Una de las razones es que el propio Git utiliza el imperativo siempre que crea un commit en tu nombre.

Por ejemplo, el mensaje por defecto creado cuando se utiliza git merge dice:

Merge branch 'myfeature'

Y cuando se utiliza git revert:

Revert "Add the thing with the stuff"This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.

O cuando se hace clic en el botón «Merge» en una solicitud de extracción de GitHub:

Merge pull request #123 from someuser/somebranch

Así que cuando escribes tus mensajes de confirmación en el imperativo, estás siguiendo las propias convenciones incorporadas de Git. Por ejemplo:

  • Refactorizar el subsistema X para facilitar la lectura
  • Actualizar la documentación de inicio
  • Quitar los métodos obsoletos
  • Liberar la versión 1.0.0

Escribir de esta manera puede ser un poco incómodo al principio. Estamos más acostumbrados a hablar en modo indicativo, que consiste en informar de los hechos. Es por eso que los mensajes de confirmación a menudo terminan leyendo como esto:

  • Arreglado el error con Y
  • Cambiando el comportamiento de X

Y a veces los mensajes de confirmación se escriben como una descripción de su contenido:

  • Más correcciones de cosas rotas
  • Dulces nuevos métodos de la API

Para eliminar cualquier confusión, aquí hay una regla sencilla para hacerlo bien siempre.

Una línea de asunto del commit de Git correctamente formada siempre debe ser capaz de completar la siguiente frase:

  • Si se aplica, este commit su línea de asunto aquí

Por ejemplo:

  • Si se aplica, este commit refactorizará el subsistema X para facilitar la lectura
  • Si se aplica, este commit actualizará la documentación de inicio
  • Si se aplica, este commit eliminará los métodos obsoletos
  • Si se aplica, este commit lanzará la versión 1.0.0
  • Si se aplica, este commit fusionará el pull request #123 de user/branch

Nota cómo esto no funciona para las otras formas no imperativas:

  • Si se aplica, este commit corregirá el error con Y
  • Si se aplica, este commit cambiará el comportamiento de X
  • Si se aplica, este commit corregirá más cosas rotas
  • Si se aplica, este commit endulzará nuevos métodos de la API

Recuerda: El uso del imperativo es importante sólo en la línea de asunto. Puedes relajar esta restricción cuando escribas el cuerpo.

Envolver el cuerpo a 72 caracteres

Git nunca envuelve el texto automáticamente. Cuando escribes el cuerpo de un mensaje de confirmación, debes tener en cuenta su margen derecho, y envolver el texto manualmente.

La recomendación es hacer esto a 72 caracteres, de modo que Git tenga mucho espacio para sangrar el texto mientras mantiene todo por debajo de 80 caracteres en total.

Un buen editor de texto puede ayudar aquí. Es fácil configurar Vim, por ejemplo, para que envuelva el texto a 72 caracteres cuando se escribe un commit de Git. Tradicionalmente, sin embargo, los IDEs han sido terribles a la hora de proporcionar un soporte inteligente para el ajuste de texto en los mensajes de confirmación (aunque en las últimas versiones, IntelliJ IDEA finalmente ha mejorado en esto).

Usa el cuerpo para explicar qué y por qué vs.

Este commit de Bitcoin Core es un gran ejemplo de cómo explicar qué ha cambiado y por qué:

commit eb0b56b19017ab5c16c745e6da39c53126924ed6Author: Pieter Wuille <[email protected]>Date: Fri Aug 1 22:57:55 2014 +0200 Simplify serialize.h's exception handling Remove the 'state' and 'exceptmask' from serialize.h's stream implementations, as well as related methods. As exceptmask always included 'failbit', and setstate was always called with bits = failbit, all it did was immediately raise an exception. Get rid of those variables, and replace the setstate with direct exception throwing (which also removes some dead code). As a result, good() is never reached after a failure (there are only 2 calls, one of which is in tests), and can just be replaced by !eof(). fail(), clear(n) and exceptions() are just never called. Delete them.

Echa un vistazo al diff completo y piensa en el tiempo que el autor está ahorrando a sus compañeros y a los futuros commits al tomarse el tiempo de proporcionar este contexto aquí y ahora. Si no lo hiciera, probablemente se perdería para siempre.

En la mayoría de los casos, se pueden omitir los detalles sobre cómo se ha hecho un cambio. El código es generalmente autoexplicativo en este sentido (y si el código es tan complejo que necesita ser explicado en prosa, para eso están los comentarios de la fuente). Concéntrese en dejar claras las razones por las que hizo el cambio en primer lugar -la forma en que las cosas funcionaban antes del cambio (y lo que estaba mal con eso), la forma en que funcionan ahora, y por qué decidió resolverlo de la manera que lo hizo.

¡El futuro mantenedor que le agradece puede ser usted mismo!

Consejos

Aprenda a amar la línea de comandos. Deja atrás el IDE.

Por tantas razones como subcomandos tiene Git, es sabio abrazar la línea de comandos. Git es increíblemente potente; los IDEs también lo son, pero cada uno de ellos de forma diferente. Yo uso un IDE todos los días (IntelliJ IDEA) y he usado otros extensamente (Eclipse), pero nunca he visto una integración de IDE para Git que pueda empezar a igualar la facilidad y el poder de la línea de comandos (una vez que la conoces).

Ciertas funciones de IDE relacionadas con Git son invaluables, como llamar a git rm cuando borras un archivo, y hacer lo correcto con git cuando renombras uno. Donde todo se desmorona es cuando empiezas a intentar hacer commit, merge, rebase, o hacer un sofisticado análisis del historial a través del IDE.

Cuando se trata de manejar todo el poder de Git, es la línea de comandos todo el camino.

Recuerda que tanto si usas Bash como Zsh o Powershell, hay scripts de finalización de pestañas que eliminan gran parte del dolor de recordar los subcomandos y conmutadores.

Lee Pro Git

El libro Pro Git está disponible online de forma gratuita, y es fantástico. Aprovéchalo.

Imagen de cabecera: xkcd

Deja una respuesta

Tu dirección de correo electrónico no será publicada.