en Programación

Cómo escribir un mensaje de commit de git

Este post es una traducción del post How to Write a Git Commit Message, de @cbeams. Este trabajo se realizo en colaboración con @may_cabrera con permiso del autor original. Gracias a ambos!

Teniendo como excusa el formato y uso de comentarios en Git, el post nos muestra diversas formas de uso de este SCV, cuestiones metodológicas y de uso cotidiano de Git. Es muy interesante en muchos sentidos, así que les recomiendo tomarse un tiempo para su lectura.

 




Introducción | Las Siete Reglas | Consejos


Introducción: ¿Por qué es importante un buen mensaje de commit?

Si navegas el registro de un repositorio Git al azar probablemente encuentres que sus mensajes de commit son mas o menos un lío. Por ejemplo, echemos un vistazo a estas gemas de mis primeros días desarrollando para 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 files
22b25e0 Consolidated Util and MutableAnnotationUtils classes into existing AsmUtils
7f96f57 polishing

Uff. Compara eso con estos commits más recientes del mismo repositorio:

$ git log --oneline -5 --author pwebb --before "Sat Aug 30 2014"

5ba3db6 Fix failing CompositePropertySourceTests
84564a0 Rework @PropertySource early parsing logic
e142fd1 Add tests for ImportSelector meta-data
887815f Update docbook dependency and generate epub
ac8326d Polish mockito usage

¿Qué prefieres leer?

El primero cambia mucho en forma y tamaño; el último es conciso y consistente. El primero es lo que ocurre por defecto; el segundo nunca ocurre por accidente.

Mientras muchos logs de repositorio se ven como el primero, hay excepciones. El kernel de Linux y git en sí son grandes ejemplos. Mira Spring Boot, o cualquier repositorio gestionado por Tim Pope .

Los contribuidores de estos repositorios saben que un mensaje de commit git bien elaborado es la mejor manera de comunicar el contexto sobre un cambio al resto de los colegas desarrolladores (y ciertamente a sí mismos en el futuro). Un diff dirá lo que ha cambiado, pero sólo el mensaje de commit puede decir correctamente por qué. Peter Hutterer señala este punto así:

Restablecer el contexto de una pieza de código es un desperdicio. No podemos evitarlo por completo, entonces nuestros esfuerzos deberían estar en reducirlo [tanto] como sea posible. Los mensajes de commits pueden hacer exactamente eso, y como resultado, el mensaje muestra si un desarrollador es un buen colaborador.

Si no te has puesto a pensar en como generar un buen mensaje de commit de git, puede ser que no hayas gastado suficiente tiempo usando git log y herramientas relacionadas. Existe un circulo vicioso aquí: Debido a que el historial de commit carece de estructura y consistencia, uno no gasta demasiado tiempo usándolo o teniéndolo en cuenta. Y debido a que no es usado o tenido en cuenta, este se mantiene sin estructura e inconsistente

Sin embargo un log cuidado es algo hermoso y útil. git blame , revert , rebase , log , shortlog y otros subcomandos cobran vida. Revisar commits y pull requests de otros se convierte en algo digno de hacerse, y de repente se puede hacer de forma independiente. Entender porque algo sucedió hace meses o años se convierte en algo no solo posible, sino también eficiente.

El éxito a largo plazo de un proyecto descansa (entre otras cosas) en su facilidad de mantenimiento, y un desarrollador tiene pocas herramientas más poderosas que el log del proyecto. Vale la pena tomarse el tiempo para aprender cómo cargarlo de una forma adecuada. Lo que puede ser una molestia en un principio pronto se convierte en hábito, y, finalmente, un motivo de orgullo y productividad para todos los involucrados.

En este artículo, me refiero sólo al elemento más básico para mantener un historial saludable de commits: cómo escribir un mensaje de commit particular. Hay otras prácticas importantes como commit squashing que no serán tratadas aquí. Tal vez lo haré en un post posterior.

La mayoría de los lenguajes de programación tienen convenciones bien establecidas de lo que conforma el estilo idiomático, es decir, de nombres y formato y cosas así. Hay variaciones en estas convenciones, por supuesto, pero la mayoría de los desarrolladores están de acuerdo en que escoger una y ajustarse a ella es mucho mejor que el caos que se produce cuando todo el mundo lo hace a su manera.

El enfoque de un equipo con su log de commits no debería ser diferente. Con el fin de crear un historial de revisiones útiles, los equipos primero deben ponerse de acuerdo sobre una convención en mensajes de commits que defina al menos las siguientes tres cosas:

Estilo. La sintaxis, los límites de márgenes, la gramática, la capitalización, la puntuación. Explica claramente estos puntos, elimina la ambigüedad y hazlo lo más claro posible. El resultado final será un log muy coherente que no sólo será fácil de leer, sino que en realidad será leído de forma regular.

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

Metadatos. ¿Cómo se debe marcar el identificador de un issue, el numero de pull request, etc. ?

Afortunadamente, hay convenciones bien establecidas sobre lo que hace a un commit un mensaje idiomático De hecho, muchas de estas convenciones se asumen como la forma determinada en ciertos comandos git. No hay nada que necesite ser reinventado. Sólo tienes que seguir las siete reglas descritas abajo y ya estarás en camino para hacer commits como un profesional.

Las siete reglas de un gran mensaje de commit de git

Tenga en cuenta: Todo esto ya ha sido dicho antes .

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

Por ejemplo:

Resumir los cambios en aproximadamente 50 caracteres o menos
 
Mas texto descriptivo, si es necesario.  Límita aproximadamente a 72 caracteres o menos. En algunos contextos, la primera línea se establece como el asunto del commit y el resto es el cuerpo. La línea en blanco que separa el asunto del cuerpo es fundamental (a menos que se omita el cuerpo por completo); diversas herramientas como `log`,` y `shortlog` y `rebase` pueden confundirse si ejecuta los dos juntos.

Explique el problema que el commit está resolviendo. Concéntrese en por qué usted está haciendo este cambio en comparación de cómo  (pues el código explica esa parte).
¿Hay efectos secundarios u otros consecuencias poco intuitivas en este cambio? Este es el lugar para explicarlos.

Otros párrafos vienen después de líneas en blanco.

 - Las viñetas o listas son aceptables también 
 - Normalmente, un guión o asterisco se utiliza para la viñeta, precedido por un solo espacio, con líneas en blanco en el medio, pero hay diferentes convenciones 

Si utiliza un administrador de "issues", coloque referencias a ellos en la parte inferior, así: 

Resuelve: # 123 
Consulte también: # 456, # 789

1. Separa el título del cuerpo del mensaje con una linea en blanco

Desde la página de manual de git commit :

Aunque no es necesario, es una buena idea iniciar el mensaje de commit con una sola linea corta (menos de 50 caracteres) que resuma el cambio, seguida de una línea en blanco y, a continuación una descripción más completa. El texto sobre la primera línea en blanco en el mensaje del commit es tratado como el título del commit, y este título se utiliza en todo Git. Por ejemplo, git-format-patch (1) convierte un commit en un correo electrónico, y utiliza el título como asunto y el resto del commit en el cuerpo.

En primer lugar, no todo commit requiere tanto un título como un cuerpo. A veces una sola línea está bien, sobre todo cuando el cambio es tan simple que agregar más contexto no es necesario. Por ejemplo:

Fix typo in introduction to user guide

No es necesario decir nada más; si el lector se pregunta cuál fue el error tipográfico, simplemente puede echar un vistazo al cambio, mediante el uso de git show o git diff o git log -p .

Si estás realizando un commit de este tipo en la línea de comandos, es fácil de usar el parametro -m para git commit :

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

Sin embargo, cuando un commit merece un poco de explicación y contexto, es necesario escribir un cuerpo. Por ejemplo:

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.

Esto no es tan fácil de hacer con el parametro -m , realmente necesitas de un editor adecuado. Si aún no dispones de un editor configurado para usar con git en la línea de comandos, lee esta sección de Pro Git .

En cualquier caso, la separación del titulo y cuerpo vale la pena cuando se navega por el log. Aquí está la entrada del log completo:

$ git log
commit 42e769bdf4894310333942ffc5a15151222a87be
Author: Kevin Flynn <kevin@flynnsarcade.com>
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 título:

$ git log --oneline
42e769 Derezz the master control program

O, git shortlog , que agrupa commits por usuario, de nuevo mostrando sólo la línea de titulo para ser conciso:

$ git shortlog
Kevin Flynn (1):
      Derezz the master control program

Alan Bradley (1):
      Introduce security program "Tron"

Ed Dillinger (3):
      Rename chess program to "MCP"
      Modify chess program
      Upgrade chess program

Walter Gibbs (1):
      Introduce protoype chess program

Hay numerosos contextos en git donde la distinción entre titulo y cuerpo entran en acción, pero ninguno de ellos funciona correctamente sin la línea en blanco en el medio.

2. Limita la línea de título a 50 caracteres

50 caracteres no es un límite estricto, sólo una regla práctica. Mantener las líneas de título en esta longitud asegura que sean legibles, y obliga al autor a pensar por un momento acerca de la forma más concisa de explicar lo que está enviando.

Consejo: Si estás teniendo dificultades para resumir, podrías estar realizando un commit con demasiados cambios de una sola vez. Intenta realizar commits atómicos (un tema para un post aparte).

La Interfaz de GitHub es plenamente consciente de estas convenciones. Te avisará si te pasas del límite de 50 caracteres:

gh1

Y truncará cualquier título de más de 69 caracteres con puntos suspensivos:

gh2

Así que intenta con 50 caracteres, pero considera como limite máximo 69.

3. Capitaliza la línea de título

Esto es tan simple como suena. Comienza todas las líneas de título con una letra mayúscula.

Por ejemplo:

  • Acelerar a 88 millas por hora

En lugar de:

  • acelerar a 88 millas por hora

4. No termines la línea de título con un punto

Usar puntuación es innecesario en las líneas de título. Además, el espacio es muy valioso cuando se está tratando de mantener en 50 caracteres o menos .

Ejemplo:

  • Abrir la ranura de la puerta de la bodega

En lugar de:

  • Abrir la ranura de la puerta de la bodega.

5. Utiliza el modo imperativo en la línea de título

Modo imperativo simplemente significa “hablar o escribir como si dieras 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án escritas en imperativo (“Limita el cuerpo a 72 caracteres”, etc).

El imperativo puede sonar un poco grosero; es por eso que a menudo no lo usamos. Pero es perfecto para el título de un commit. Una razón para esto es que git mismo utiliza el imperativo cada vez que crea un commit con tu nombre.

Por ejemplo, el mensaje predeterminado creado al utilizar git merge es:

Merge branch 'myfeature'

Y al usar git revert :

Revert "Add the thing with the stuff"

This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.

O cuando se hace clic en el botón “Merge” en un pull request de Github

Merge pull request #123 from someuser / somebranch

Así que cuando escribas mensajes de commit en forma imperativa, realmente estás siguiendo las mismas convenciones incorporadas por git. Por ejemplo:

  • Refactor subsystem X for readability
  • Update getting started documentation
  • Remove deprecated methods
  • Release version 1.0.0

Escribir de esta manera puede ser un poco incómodo al principio. Estamos más acostumbrados a hablar en el modo indicativo, que está más relacionado para informar hechos. Es por eso que los mensajes de commits terminan leyéndose así:

  • Fixed bug with Y
  • Changing behaviour of X

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

  • More fixes broken stuff
  • Sweet new API methods

Para eliminar cualquier confusión, aquí hay simple regla para hacerlo bien cada vez.

Un commit de git formado adecuadamente siempre debe ser capaz de completar la siguiente frase:

  • If applied, this commit will your subject line here

Por ejemplo:

  • If applied, this commit will refactor subsystem X for readability
  • If applied, this commit will update getting started documentation
  • If applied, this commit will remove deprecated methods
  • If applied, this commit will release version 1.0.0
  • If applied, this commit will merge pull request #123 from user/branch

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

  • If applied, this commit will fixed bug with Y
  • If applied, this commit will changing behaviour of X
  • If applied, this commit will more fixes for broken stuff
  • If applied, this commit will sweet new API methods

Recuerda: El uso del imperativo es importante sólo en el título. Puedes omitir esta restricción cuando estés escribiendo el cuerpo

6. Ajusta el cuerpo a 72 caracteres

Git nunca ajusta el texto automáticamente. Cuando escribes el cuerpo de un mensaje de commit, debes recordar su margen derecho, y ajustar el texto manualmente.

La recomendación es hacer esto en 72 caracteres, por lo que git tiene mucho espacio para indentar texto mientras se mantiene todo debajo de 80 caracteres en general.

Un buen editor de texto puede ayudar aquí. Es fácil de configurar en Vim, por ejemplo, para ajustar el texto a 72 caracteres cuando se está escribiendo un git commit. Tradicionalmente, sin embargo, los IDEs han sido desastrosos para proveer un apoyo inteligente en el ajuste de texto en los mensajes de commit (aunque en las versiones recientes, IntelliJ IDEA ha conseguido finalmente mejorar sobre esto).

7. Utilizar el cuerpo para explicar qué y porqué en lugar de como

Este commit del repositorio Bitcoin Core es un gran ejemplo de sobre explicar lo que ha cambiado y por qué:

commit eb0b56b19017ab5c16c745e6da39c53126924ed6
Author: Pieter Wuille <pieter.wuille@gmail.com>
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 una mirada al diff completo y sólo piensa en la cantidad de tiempo que el autor le ahorro a los colegas y futuros desarrolladores por tomarse el tiempo para proporcionar este contexto, aquí y ahora. Si él no lo hubiera hecho, esto probablemente se perdería para siempre.

En la mayoría de los casos, puedes ignorar los detalles sobre cómo se ha hecho un cambio. El código es generalmente auto-explicativo en este sentido (y si el código es tan complejo como para necesitar ser explicados en prosa, esa es la función de los comentarios en el código fuente). Sólo céntrate en aclarar las razones por las que has realizado el cambio, como funcionaban las cosas antes del cambio (y que había de malo con eso), la forma en que funciona ahora, y por qué decidiste resolverlo de la forma en la que lo hiciste.

¡El futuro programador agradecido puedes ser tú mismo!

Consejos

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

Debido a la gran cantidad de subcomandos git que hay, es prudente adoptar la línea de comandos. Git es increíblemente poderoso; los IDEs lo son tambien, pero cada uno a su manera. Yo uso un IDE todos los días (IntelliJ IDEA) y he utilizado otros extensivamente (Eclipse), pero nunca he visto una integración del IDE con git que coincida con la facilidad y el poder de la línea de comandos (una vez que lo sepas hacer).

Ciertas funciones de los IDE relacionadas con git son invaluables, como llamar a git rm cuando eliminamos un archivo, y hacer las cosas bien con git al renombrarlo. Todo se cae cuando se comienza a intentar hacer commits, merge, rebase, o hacer un análisis sofisticado de la historia a través del IDE.

Cuando se trata de utilizar todo el poder de git, la línea de comandos es la manera.

Recuerda que si usas Bash o Z shell, hay scripts de autocompletado que alivian gran parte del dolor de recordar los subcomandos.

Lee Pro Git

El libro Pro Git está disponible en línea de forma gratuita, y es fantástico. ¡Aprovechalo!

Loading Facebook Comments ...

¿Algo para decir?

Comentario

  1. Buen post! Si tuviera puntines te llevarías los diez. Yo he cometido innumerables veces las barbaridades que se mencionan en el artículo y lentamente (creo que) voy mejorando.
    Puntualmente, la regla 7 es fundamental. La 4 tiene sentido, pero aún me cuesta acostumbrarme. Y para la 5, me cuesta pensarlo en español: el imperativo me suena mal…

    de aplicarse, este commit… “Remover métodos obsoletos”?
    de aplicarse, este commit… “Mezclar el pull request #123”?

    Las siguientes quedan un poco mejor,

    de aplicarse, este commit… “Removerá métodos obsoletos”?
    de aplicarse, este commit… “Mezclará el pull request #123”?
    o bien
    al aplicar este commit… “Se remueven métodos obsoletos”?
    al aplicar este commit… “Se mezcla el pull request #123”?

    pero no son órdenes. Alguna alternativa más fina?

    • La regla 7 expresa claramente que dejemos de hacer nuestros algoritmos totalmente faltos de expresividad. Por ese lado, estuvo haciendo algunas lecturas de Clean Code, donde llevan al extremo la idea de que “El código en si mismo es la documentación”. De esta forma, no hay motivos para explicar el como en otro lado (Ni en comentarios dentro del código, ni mucho menos en el repositorio ni en el issue tracker).

      Cuando necesitamos explicar el como en el commit, es porque la deuda técnica es mayor a lo tolerable.

      Sobre la 5, me cuesta mucho, pero pienso que es lo que propones o agregar adelante un “Debe remover…”, “Debe mezclar…”, pero me suena mas forzado. La idea del “Se…” tampoco me gusta. Si tuviera que quedarme con una, usaría la primera, aunque no sean ordenes, son consecuencias de una acción. La otra:

      de aplicarse, este commit… “Remueve métodos obsoletos”
      de aplicarse, este commit… “Mezcla el pull request #123”

      Pero las veo como alternativas, me parece que lo importante es “ “.

      • Genial. Compro esta última forma que mencionas, que además asocia las reglas 5 y 7 en una sola. Entonces la pregunta para armar el título de un cambio pasa a ser la siguiente: “qué hace este commit?”

        qué hace este commit? este commit… Remueve métodos obsoletos
        qué hace este commit? este commit… Mezcla el pull request #123
        qué hace este commit? este commit… Agrega el soporte para proxy servers

        eventualmente, el “por qué se hace?” queda para la descripción, y el “cómo lo hace?” es el código mismo.
        Abrazo!

Loading Disqus Comments ...