17 juillet 2018 | Git | Olivier Revial

Git : le message de commit parfait

Temps de lecture estimé : 9 minutes

Quels que soient nos langages ou nos outils de prédilection, il y a bien une chose que nous faisons tous au quotidien : des commits !

Mais utilisons-nous des messages de commit utiles, et d’ailleurs, à quoi est-ce que ça sert ? C’est ce que nous allons voir dans cet article.

Réfléchir au message de commit ? Pff, pour quoi faire ?

Oui c’est vrai, pourquoi au juste devrait-on s’embêter à avoir des conventions de commits alors qu’on s’en sort très bien avec nos messages actuels ?

CommitStrip strip

Regardons vite un petit exemple d’historique Git :

49ff1d07 fix search issue
59a4d13e add ci
44e2f204 add test on search component
03d00e2e final commit for this **** bug
01eb12bb test...
10d42648 really fixed bug
bab7be76 fix bug on user screen (SOM-245)
4a267eb6 improve user screen
21518e0c add user screen (first version)
a2fdd7d4 SOM-213 : fixes cart issue when an user tries to add the same product for the second time and quantity is greater than 2
c5ff8f0a update cart to improve purchase process

😰 Si vous avez aussi commencé à transpirer en voyant cet historique, c’est que vous commencez à voir pourquoi il est important d’avoir des messages de commit parlants.

Faciliter la relecture

On le sait tous, le code n’est pas figé et il évolue en permanence. Et lorsqu’on a besoin de faire un refactoring, d’ajouter une nouvelle fonctionnalité ou d’aller corriger un bug, il est pratique de pouvoir aller consulter l’historique des commits pour savoir qui a fait quoi, quand et pour quelle raison. Avoir des conventions de commit permet entre autres :

  • d’homogénéiser les messages et ainsi de faciliter la relecture de l’historique
  • d’avoir rapidement du contexte sur le commit : pourquoi le commit a été fait, quelle est l’issue Gitlab ou Jira associée, etc.

Réfléchir à ce qu’on va pousser

Ce que j’adore avec l’adoption de conventions de messages de commit c’est qu’elle oblige chaque développeur à vraiment se poser la question : Qu’est-ce que je suis en train de commiter ?

Si cela peut sembler trivial, c’est pourtant loin d’être inutile et cela peut parfois permettre de remettre en question ce que l’on est en train de faire. Est-ce que les fichiers que je vais committer doivent bien faire partie d’un seul et même commit ? Se poser toutes ces questions permet à terme de bien découper l’écriture de son code, et surtout d’y réfléchir en amont, en gardant toujours à l’esprit le problème initial auquel on veut répondre.

J’y reviendrai dans le chapitre sur l’hygiène de commit.

Générer des changelogs automatiquement

Avoir des messages de commit parlants permet également de générer automatiquement différents types de rapports, notamment des changelogs qui vont permettre de suivre l’évolution d’une application facilement.

Une image valant mille mots, est-ce que vous préférez ce changelog :

… ou celui-là ?

Étant donné qu’il existe plein d’outils pour générer des changelogs à partir des commits, autant ne pas faire le travail deux fois et démarrer dès le début avec des bons messages de commits !

Le bon message de commit

Maintenant que vous êtes convaincus de l’utilité d’avoir une convention de messages de commit (j’espère en tout cas 😳), voyons comment écrire un bon messsage de commit.

Autant sur le fond que sur la forme, le message de commit est comparable à… l’e-mail ! ✉ Avant que vous ne partiez en courant, je vais expliquer pourquoi. Pour faire simple, un message de commit devrait contenir dans l’idéal :

  • Un sujet qui décrit ce que font les changements introduits
  • Un corps (optionnel mais recommandé) qui décrit pourquoi les changements ont été introduits
  • Un footer (optionnel) qui référence d’éventuelles métadonnées liées au commit : issue Gitlab, ticket Jira, autre merge request, etc.

Il est essentiel de garder en tête que le message de commit doit répondre aux questions “Quoi ?” et “Pourquoi ?”, mais surtout pas à la question “Comment ?”. En effet, la réponse au “Comment ?” est déjà donnée par le diff du code, le spécifier dans le message n’apporte rien de plus. De plus, si le détail de l’implémentation nécessite de plus amples explications, ces explications devraient être présentes autour du bout de code en question.

En écrivant un bon message de commit on cherche donc à bien expliquer les raisons pour lesquelles on a introduit les changements, c’est-à-dire expliquer :

  • Comment les choses fonctionnaient avant le commit
  • Ce qui n’allait pas dans l’ancien code
  • Comment les choses fonctionnent maintenant
  • Pourquoi on a décidé d’implémenter les changements de la manière dont on l’a fait

Le sujet

XKCD strip

Comme l’objet d’un e-mail, la première ligne d’un message de commit permet de répondre à la question : “Quoi ?”. Le but est donc de décrire brièvement (en 50 caractères max) ce qui a été fait, il s’aigt donc de faire un résumé des changements introduits.

Concernant la forme, les recommandations sont les suivantes :

  • 50 caractères maximum. Cette contrainte n’est pas obligatoire mais elle permet de faciliter la lecture sur les outils type git log (notamment en oneline) qui vont limiter le nombre de caractères affichés sans retour à la ligne (on “perd” donc une partie du message à la lecture).
  • Utiliser uniquement le présent des verbes et l’impératif (on préférera donc Fix à Fixes ou Fixed). Ne pas le faire n’altérera pas la compréhension mais cette convention permet d’avoir plus de cohérence sur un historique de commit, et le choix du présent des verbes est cohérent avec ce que génèrent des outils comme git merge (Merge branch my-awesome-feature) ou encore git revert (Revert “add user cart” … This reverts commit ce4097ff471c2c99d29afd360a2adf37147afdb2).
  • Le sujet ne doit pas terminer par un point
  • Le sujet doit commencer par une majuscule. Attention, nous verrons plus loin que l’on peut parfois déroger à cette règle lors de l’utilisation du conventional changelog.

💡 Astuce 💡

Lorsque vous écrivez un sujet de commit, une excellente astuce donnée par Chris Beams consiste à vérifier que le sujet du commit peut compléter la phrase “If applied, this commit will subject content here”. Ainsi, on distingue très rapidement les bons des mauvais sujets de commit, comme le montre l’exemple ci-dessous.

  • If applied, this commit will reorganize imports into user service
  • If applied, this commit will release version 1.3.2
  • If applied, this commit will fix order duplication issue
  • If applied, this commit will new awesome feature on cart
  • If applied, this commit will fixed order duplication issue
  • If applied, this commit will various fixes on user cart

Le corps

En sautant une ligne, on peut commencer à écrire une description plus longue, mais cette fois on va tenter de répondre plutôt à la question “Pourquoi ?”. Cette partie peut être très importante puisqu’elle va permettre à un développeur qui revient sur ce commit longtemps après sa création de savoir pourquoi il a été introduit. Cela permet par exemple de savoir pourquoi telle ou telle correction a été implémentée ici, pourquoi une fonctionnalité a été ajoutée, etc. Il est bien sûr possible de déporter toutes ces informations dans un outil externe comme un outil de ticketing, mais je recommanderais plutôt d’avoir les explications qui vivent proches du code, cela évite des allers-retours constants entre le code et l’outil de ticketing, des informations qui ne sont pas à jour et ainsi de suite.

Sur la forme, il est possible d’écrire autant de lignes que nécessaire pour expliquer le contexte du commit, le pourquoi. On peut également faire des sauts de ligne ou utiliser des listes à puces. Voici quelques recommandations :

  • Toujours sauter une ligne entre le sujet et le corps. Ceci est essentiel pour avoir un affichage correct sur certains outils (par exemple git log en oneline).
  • Les listes à puces peuvent être utilisées avec - ou * (comme en Markdown)
  • Chaque ligne du corps de message doit idéalement faire 72 caractères au maximum. Encore une fois cela permet ensuite de faciliter la lecture sur les outils type git log.

Parmi les bonnes pratiques de commit on retrouve souvent le footer qui est un peu l’équivalent de la pièce-jointe (allez promis c’est la dernière référence au mail…), on va donc pouvoir faire des liens vers des ressources externes. C’est typiquement l’endroit où on référence un ticket Jira ou une issue Gitlab, comme le mentionne Kevin dans son article sur le conventional changelog

Un exemple peut-être ?

Voici un exemple d’excellent message de commit, écrit par un certain Linus Torvald :

Teach dump_page() to correctly output poisoned struct pages

If struct page is poisoned, and uninitialized access is detected via
PF_POISONED_CHECK(page) dump_page() is called to output the page.  But,
the dump_page() itself accesses struct page to determine how to print
it, and therefore gets into a recursive loop.

For example:

  dump_page()
   __dump_page()
    PageSlab(page)
     PF_POISONED_CHECK(page)
      VM_BUG_ON_PGFLAGS(PagePoisoned(page), page)
       dump_page() recursion loop.

Link: http://lkml.kernel.org/r/20180702180536.2552-1-pasha.tatashin@oracle.com
Fixes: f165b37 ("mm: uninitialized struct page poisoning sanity checking")
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Note : Le tout début du sujet a été modifié car il utilisait un préfixe interne au projet Linux.

Hygiène de commit 🛁

A ce stade nous avons vu comment bien structurer un message de commit Git, et avec quel contenu.

Pour aller plus loin, je conseille vivement d’adopter la technique du conventional changelog expliquée par Kevin qui permet de rajouter plus de contexte dans le message de commit et ainsi d’améliorer encore la lisibilité et de faciliter la génération automatique de changelog. Cette technique, combinée à toutes les conventions de nommage et la réfléxion du quoi et pourquoi de nos changements devrait permettre une meilleure “hygiène de code”.

En effet, réfléchir au type de commit (feature, test, refactoring, …) ainsi qu’à son contenu permet de se poser les bonnes questions et on s’aperçoit bien vite lorsqu’il y a des choses incohérentes. Lorsqu’on a à la fois écrit une nouvelle fonctionnalité, fait du refactoring sur une méthode et rajouté des tests sur une autre fonctionnalité, on voit bien qu’il est impossible d’écrire un message de commit qui respecte à la fois les conventions données dans cet article et la technique du conventional changelog. Cela force donc à se poser les bonnes questions : est-ce que je ne devrais pas découper mes changements en plusieurs commits ?.

Conclusion

Si ce genre de bonnes pratiques peuvent parfois paraître un peu rebutantes au début, s’imposer cette rigueur est un excellent moyen de se poser les bonnes questions sur son code. De mon point de vue cela va beaucoup plus loin que le simple historique Git : soigner ses commits en découpant logiquement les changements et en expliquant bien pourquoi ils ont été introduits permet au développeur d’être sûr que le code qu’il pousse est en cohérence avec ce qui est attendu, et cela apporte un énorme contexte autour du code qui facilitera la vie de tous les développeurs dans les futures maintenances du code, vous compris !

Alors aidez votre “vous” du futur, appliquez-vous lors de la rédaction de vos commits !


Références :

Git
comments powered by Disqus