Lors du précédent article sur Git, nous avons vu les bases de Git, notamment comment commiter (sauvegarder) et partager rapidement son travail. Revenons plus en détail sur la phase de comment : Comment s’assurer de créer un commit cohérent avec un message standardisé.

Précédemment…

ActionCommande
Cloner un projet en localgit clone <url>
Valider les modifications d’un ou plusieurs fichier pour le prochain commitgit add <files>
Créer un nouveau point de sauvegarde : commitergit commit -m"<explicit message>"
Récupérer en local les dernières modifications présentes sur le serveurgit pull
Envoyer ses commits sur le serveurgit push

Commiter proprement : L’indispensable

Que ce soit en équipe ou pour un projet en solo, l’historique d’un projet est un outil clé dans le développement informatique. Représenté par la suite de commits qui composent la branche courante, il permet de revenir à une version antérieur, de vérifier les dernières modifications et comprendre le l’évolution du projet. Il est souvent recommandé d’écrire de « petits » commits, facilitant la relecture par ses pairs et l’intégration des modification.

Commiter correctement est donc primordial tant pour l’avancée d’un projet que pour le moral des développeurs… Pour y parvenir, il faut dans un premier temps vérifier ce que l’on commite, c’est-à-dire quelles modifications sur quels fichiers, puis écrire un message de commit clair et explicite.

Avant tout, se repérer dans Git

La première étape pour commiter proprement est de s’assurer d’ajouter (git add) les bons fichiers au bon moment, ni plus, ni moins. Pour cela, git status permet de vérifier quels fichiers sont marqués pour le prochain commit, lesquels sont modifiés mais non marqués, ou encore complètement ignorés par Git.

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   .gitignore

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   build.gradle

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    test.md

Ici, 3 fichiers ont des modifications qui ne sont pas dans le dernier commit :

  • .gitignore a été modifié et cette modification sera prise en compte dans le prochain commit (Changes to be committed).
  • build.gradle a été modifié mais cette modification ne sera pas prise en compte dans le prochain commit (Changes not staged for commit).
  • test.md quant à lui n’a jamais fait parti d’un précédent commit et ne sera pas pris en compte dans le prochain.

Utiliser git status avant de commiter permet de vérifier les fichiers effectivement pris en compte, et d’éviter de commiter un fichier indésirable (fichier de configuration locale, fichier temporaire…).

On peut noter au passage que git status indique également le nom de la branche courante et si celle-ci est à jour par rapport au serveur git

On branch master
Your branch is up-to-date with 'origin/master'.

Attention ! Détail important, git add manipule en réalité des modifications et non pas des fichiers. Ce que cela implique ? Si je modifie un fichier après avoir utilisé git add, les nouvelles modifications ne seront pas prises en compte. On peut donc avoir un fichier apparaissant à la fois dans Changes to be committed et dans Changes not to be committed. Pour intégrer ces nouvelles modifications dans le prochain commit, il faudra de nouveau utiliser git add sur ce fichier.

Maintenant que l’on est sûrs d’avoir ajouté les bons fichiers pour le prochain commit, une dernière vérification s’impose. Pour jeter un dernier œil aux modifications qui seront commitées, pour… par exemple… éviter un print("plouf") en production 😉

Pour cela, deux version de git diff sont utiles :

  • git diff seul permet de lister les modifications not staged for commit
  • git diff --staged qui lui liste les modifications to be committed

Dans les deux cas, git affiche les lignes modifiées dans les fichiers correspondants

diff --git a/.gitignore b/.gitignore
index d50d065..7c57645 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,11 +11,11 @@
+ # Created by https://www.gitignore.io/api/git
+ # Edit at https://www.gitignore.io/?templates=git
+
+ ### Git ###
+ # Created by git for backups. To disable backups in Git:
+ # $ git config --global mergetool.keepBackup false
+ *.orig
+
+ # Created by git when using merge tools for conflicts
+ *.BACKUP.*
+ *.BASE.*
+ *.LOCAL.*
+ *.REMOTE.*
+ *_BACKUP_*.txt
+ *_BASE_*.txt
+ *_LOCAL_*.txt
+ *_REMOTE_*.txt
+
+ # End of https://www.gitignore.io/api/git

Assez intuitivement, on comprendra que les lignes précédées d’un + sont des lignes ajoutées au fichier, et inversement pour les lignes commençant par un -.

Rédiger ses messages de commit

Bien, maintenant que les modifications à enregistrer sont validées, il s’agit de créer un message de commit cohérent et explicite. Explicite avec un message de commit expliquant succinctement ce qu’apportent ces modifications, et cohérent en suivant une convention d’écriture, par exemple le conventional commit.

Conventional Commit

Dans sa forme la plus simple, le conventional commit ressemble à ceci : <type>: <description>. Il peut être bien plus étendu, mais se forcer à respecter cette forme minimal est déjà une bonne pratique qui rendra l’historique plus lisible. Le <type> de commit est tiré de la liste ci-dessous (source). Pour l’ajout d’une nouvelle fonctionnalité on utilisera le type feat, pour l’ajout de la CI dans Gitlab ci sera tout indiqué, etc…

Type de commitTitreDescription
featFeaturesUne nouvelle fonctionnalité
fixBug FixesCorrection de bug
docsDocumentationChangements dans la documentation
styleStylesChangements qui n’affectent pas la signification du code (espaces, formattage, missing, typographies, etc)
refactorCode RefactoringRefactorisation du code (déplacement de code, renommage, …)
perfPerformance ImprovementsChangement dans le code pour améliorer les performances
testTestsAjout ou correction de tests (unitaires, fonctionnels…)
buildBuildsChangements affectant la compilation du projet ou ses dépendances (maven, gradle, npm…)
ciContinuous IntegrationsModifications de la configuration de la CI du projet (Jenkins, Gitlab CI, Tracis…)
choreChoresAutres modifications qui n’affectent pas les fichiers sources ou de tests
revertRevertsAnnule un précédent commit

L’utilisation d’un seul type par commit nous ramène à un point important dans git : un commit doit avoir une cohérence en lui-même. Il ne peut donc avoir qu’un seul type ! Si ce n’est pas le cas, dans la majorité des cas, c’est qu’il devrait être découpé. Je découvre un petit bug en implémentant une nouvelle fonctionnalité ? Les modifications qui fix ce bug seront mises dans un commit à part tagué fix, le reste fera l’objet d’un commit de feat.

La <description> est une phrase courte qui explique succinctement ce qu’apporte le commit. Pour faciliter la rédaction, cette description peut continuer la phrase « Appliquer ce commit… », par exemple « Appliquer ce commit active la CI dans Gitlab ».

Grâce à cela, les messages de commits seront standardisés, plus faciles à lire et rendront l’historique de commit plus clair !