Les commits Git sont des éléments fondamentaux d’un dépôt Git (Git Repository), sans oublier les messages de commit qui constituent un véritable journal de bord pour le dépôt. Au fur et à mesure que le projet ou le dépôt évolue dans le temps (avec l’ajout de nouvelles fonctionnalités, la correction de bugs, la refonte de l’architecture), les messages de commit permettent de suivre et de comprendre les modifications apportées. Ces messages doivent donc résumer de manière courte et précise les changements effectués.
Qu’est-ce qu’un commit Git ?
Les messages de commit Git sont les empreintes laissées sur le code que vous modifiez. Lorsque vous consultez votre code un an plus tard, avoir rédigé un message clair vous aide à comprendre plus facilement et rapidement les raisons derrière vos choix de développement. De plus, ces messages facilitent la collaboration avec vos collègues. Avec des commits Git isolés en fonction du contexte, il est plus rapide pour les développeurs et développeuses de détecter un bug introduit par un seul commit et d’y revenir dessus.
Dans le cadre de projets d’envergure, où de nombreuses parties sont ajoutées, modifiées ou supprimées constamment, s’assurer que les messages de commit soient correctement maintenus peut parfois être une tâche compliquée, particulièrement sur les projets qui s’étendent sur plusieurs semaines ou plusieurs mois.
Pour vous aider à maintenir un historique de commits Git précis, découvrez dans cet article un certain nombre de situations auxquelles les développeurs et développeuses peuvent être confrontés au quotidien :
- Situation 1 : Je dois modifier le commit le plus récent
- Situation 2 : Je dois modifier un commit Git spécifique
- Situation 3 : Je dois ajouter, combiner ou supprimer un commit Git
- Situation 4 : Mon historique de commits Git est incohérent, je veux repartir à zéro
Remarque : cet article suppose que vous ayez déjà des connaissances sur les fondamentaux de Git comme le fonctionnement des branches, l’ajout de modifications non validées d’une branche à l'étape du staging et la validation des modifications. Vous souhaitez en savoir plus sur ces éléments ? Consultez notre documentation avant de continuer la lecture de cet article.
Avant d’entrer dans le vif du sujet, regardons brièvement à quoi ressemble un workflow de développement dans le cadre d’un projet Ruby on Rails hypothétique.
Exemple de commit Git
Dans cet exemple, nous avons besoin d’ajouter une vue de navigation sur la page d’accueil, ce qui implique la mise à jour et l’ajout de nombreux fichiers.
Voici le déroulement de l’ensemble du processus étape par étape :
-
Vous commencez à travailler sur une fonctionnalité avec la mise à jour d’un fichier que nous appelons
application_controller.rb
-
Cette fonctionnalité requiert la mise à jour d’une vue :
index.html.haml
-
Vous avez ajouté un partiel utilisé dans la page d’index :
_navigation.html.haml
-
Les styles de la page doivent également être mis à jour pour refléter le partiel ajouté :
styles.css.scss
-
La fonctionnalité est maintenant prête avec les modifications souhaitées, il est temps de mettre à jour les tests. Les fichiers à mettre à jour sont :
application_controller_spec.rb
navigation_spec.rb
-
Les tests sont mis à jour et fonctionnent comme prévu. Désormais, il est temps de valider les changements.
Puisque tous les fichiers appartiennent à différentes parties de l’architecture, nous validons les modifications de manière isolée les unes des autres afin d’assurer que chaque commit représente un certain contexte et soit dans le bon ordre. Les changements des commits Git s’ordonnent généralement comme suit : en commençant par le backend, suivi de la couche intermédiaire puis du frontend.
application_controller.rb
&application_controller_spec.rb
; Add routes for navigation._navigation.html.haml
&navigation_spec.rb
; Page Navigation View.index.html.haml
; Render navigation partial.styles.css.scss
; Add styles for navigation.
Maintenant que nos changements sont validés, il est possible de créer une merge request (requête de fusion) avec la branche. Une fois la merge request ouverte, celle-ci est généralement examinée par un pair avant que les changements ne soient fusionnés dans la branche principale du dépôt Git. Maintenant, observons les différentes situations dans lesquelles vous pouvez vous trouver lors de la révision du code.
Situation 1 : comment modifier le commit Git le plus récent ?
Imaginez que le relecteur examine le fichier styles.css.scss
et suggère une modification. Dans ce cas, il est très simple d’effectuer cette modification car les changements de la feuille de style font partie du dernier commit sur votre branche.
Voici comment s’y prendre :
-
Vous effectuez directement les changements nécessaires dans
styles.css.scss
dans votre branche actuelle. -
Une fois les changements effectués, ajoutez ces modifications au staging; exécutez
git add styles.css.scss
. -
Dès que les changements sont pris en compte, ajoutez-les à votre dernier commit; exécutez la commande
git commit --amend
.- Explication de la commande : Ici, nous demandons à la commande
git commit
d’inclure tout ce qui est présent dans le staging au commit le plus récent.
- Explication de la commande : Ici, nous demandons à la commande
-
Cela ouvrira votre dernier commit dans l’éditeur de texte défini par Git contenant le message de commit « Add styles for navigation ».
-
Comme nous avons seulement mis à jour la déclaration CSS, nous n’avons pas besoin de modifier le message de commit. À ce stade, vous pouvez simplement enregistrer et quitter l’éditeur de texte que Git a ouvert et vos changements apparaîtront dans le commit.
Puisque vous avez modifié un commit Git existant, vous devez pousser ces changements vers le dépôt distant (« remote repository ») grâce à la commande : git push --force-with-lease <remote_name> <branch_name>
. Celle-ci va remplacer le commit Add styles for navigation
sur le dépôt distant, par le commit mis à jour à l’instant dans notre dépôt local.
Gardez en tête que lorsque vous travaillez à plusieurs sur la même branche, le fait de pousser un commit de force peut causer des problèmes pour les autres utilisateurs. En effet, ces derniers peuvent rencontrer des difficultés au moment de pousser normalement leurs changements sur une branche distante contenant de nouveaux commits poussés de force. Par conséquent, utilisez cette fonctionnalité avec prudence. Apprenez-en davantage sur les Git Push dans la documentation de Git.
Situation 2 : comment modifier les changements d’un commit Git spécifique ?
Dans l’exemple précédent, le changement du commit Git était plutôt simple car vous deviez seulement modifier le dernier commit Git. Maintenant, imaginons que le relecteur avait suggéré de modifier un élément dans _navigation.html.haml
. Dans cette situation, la modification doit se faire au niveau du deuxième commit en partant du haut. Il est donc nécessaire d’employer une autre méthode pour le changer.
Chaque fois qu’un commit est effectué dans une branche, il est identifié par une chaîne de caractères représentant un hachage SHA-1. Cet identifiant unique permet de distinguer un commit d’un autre. Vous pouvez voir tous les commits précédents, ainsi que leurs hachages SHA-1 dans une branche en exécutant la commande git log
.
Vous obtiendrez alors un résultat qui ressemble à peu près à une liste où les commits les plus récents sont en haut :
commit aa0a35a867ed2094da60042062e8f3d6000e3952 (HEAD -> add-page-navigation)
Author: Kushal Pandya <[email protected]>
Date: Wed May 2 15:24:02 2024 +0530
Add styles for navigation
commit c22a3fa0c5cdc175f2b8232b9704079d27c619d0
Author: Kushal Pandya <[email protected]>
Date: Wed May 2 08:42:52 2024 +0000
Render navigation partial
commit 4155df1cdc7be01c98b0773497ff65c22ba1549f
Author: Kushal Pandya <[email protected]>
Date: Wed May 2 08:42:51 2024 +0000
Page Navigation View
commit 8d74af102941aa0b51e1a35b8ad731284e4b5a20
Author: Kushal Pandya <[email protected]>
Date: Wed May 2 08:12:20 2024 +0000
Add routes for navigation
C’est ici que la commande git rebase
entre en jeu. Chaque fois que vous souhaitez modifier un commit spécifique avec la commande git rebase
, vous devez d’abord rebaser votre branche en déplaçant le HEAD juste avant le commit que vous souhaitez modifier. Dans le cas présent, nous devons changer le commit Page Navigation View
.
Notez ici le hachage du commit qui se trouve juste avant celui que nous souhaitons modifier.
Copiez le hachage et effectuez les étapes suivantes :
- Rebasez la branche pour vous positionner sur le commit précédant votre commit cible. Exécutez
git rebase -i 8d74af102941aa0b51e1a35b8ad731284e4b5a20
.- Explication de la commande Git : ici, vous exécutez la commande
rebase
de Git en mode interactif avec le hachage SHA-1 comme commit sur lequel se rebaser.
- Explication de la commande Git : ici, vous exécutez la commande
- Votre éditeur de texte s’ouvre et affiche tous vos commits effectués après le commit sur lequel vous vous rebasez.
Ce qui va correspondre à :
pick 4155df1cdc7 Page Navigation View
pick c22a3fa0c5c Render navigation partial
pick aa0a35a867e Add styles for navigation
# Rebase 8d74af10294..aa0a35a867e onto 8d74af10294 (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove Git commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
Chaque commit est précédé du mot pick
. Ci-dessous, vous retrouverez tous les mots-clés disponibles. Pour éditer un commit, vous devez changer pick 4155df1cdc7 Page Navigation View
en edit 4155df1cdc7 Page Navigation View
. Sauvegardez les changements et quittez l’éditeur.
Votre branche est désormais rebasée à l’endroit précédent le commit qui incluait _navigation.html.haml
. Ouvrez le fichier et effectuez les modifications souhaitées selon les retours de vos pairs. Une fois les changements terminés, intégrez-les en exécutant git add _navigation.html.haml
.
Maintenant que les changements sont intégrés, il est temps de ramener la branche HEAD au commit initial (en incluant les modifications apportées). Exécutez git rebase -–continue
.
Votre éditeur par défaut s’ouvrira dans le terminal et affichera le message de commit modifié lors du rebasage : Page Navigation View
. Vous pouvez modifier ce message si vous le souhaitez. Néanmoins, il est préférable de le laisser tel quel. Enregistrez et quittez l’éditeur.
À ce stade, Git réexécutera tous les commits qui ont suivi après le commit que vous venez de modifier et maintenant la branche HEAD est de retour au commit supérieur que vous aviez initialement. Il inclut également les nouveaux changements que vous avez apportés à l’un des commits.
Puisque vous avez modifié un commit déjà présent dans le dépôt distant, vous devez à nouveau pousser de force cette branche en exécutant : git push --force-with-lease <remote_name> <branch_name>
.
Situation 3 : comment ajouter, combiner ou supprimer des commits Git ?
Il arrive régulièrement que l'on ajoute plusieurs commits pour corriger des éléments déjà validés. Il est possible de les réduire tout en les combinant avec les commits initiaux.
Pour cela, commencez le rebase interactif comme vous le feriez dans d’autres scénarios :
pick 4155df1cdc7 Page Navigation View
pick c22a3fa0c5c Render navigation partial
pick aa0a35a867e Add styles for navigation
pick 62e858a322 Fix a typo
pick 5c25eb48c8 Ops another fix
pick 7f0718efe9 Fix 2
pick f0ffc19ef7 Argh Another fix!
Si vous souhaitez combiner toutes ces modifications dans c22a3fa0c5c Render navigation partial
, vous devez :
-
Déplacer les corrections afin de les placer juste en-dessous du commit que vous désirez garder à la fin.
-
Changer
pick
ensquash
oufixup
pour chacune des modifications.
Remarque: squash
conserve les messages de commit des corrections dans la description. Fixup
oublie les messages de commit des corrections et conserve l’original.
Vous obtenez donc :
pick 4155df1cdc7 Page Navigation View
pick c22a3fa0c5c Render navigation partial
fixup 62e858a322 Fix a typo
fixup 5c25eb48c8 Ops another fix
fixup 7f0718efe9 Fix 2
fixup f0ffc19ef7 Argh Another fix!
pick aa0a35a867e Add styles for navigation
Enregistrez les changements et quittez l’éditeur. Voici le résultat :
pick 4155df1cdc7 Page Navigation View
pick 96373c0bcf Render navigation partial
pick aa0a35a867e Add styles for navigation
Comme précédemment, vous avez juste besoin d’exécuter git push --force-with-lease <remote_name> <branch_name>
et les changements sont appliqués.
Si vous souhaitez supprimer un commit Git de la branche, utilisez plutôt la commande drop
ou effacez la ligne. Nous conseillons d’éviter les commandes squash
et fixup
pour cela.
Comment éviter les conflits entre commits ?
Pour éviter tout conflit, assurez-vous que les commits que vous faites remonter n’impactent pas de fichiers modifiés par des commits suivants.
pick 4155df1cdc7 Page Navigation View
pick c22a3fa0c5c Render navigation partial
fixup 62e858a322 Fix a typo # this changes styles.css
fixup 5c25eb48c8 Ops another fix # this changes image/logo.svg
fixup 7f0718efe9 Fix 2 # this changes styles.css
fixup f0ffc19ef7 Argh Another fix! # this changes styles.css
pick aa0a35a867e Add styles for navigation # this changes index.html (no conflict)
Situation 4 : mon historique de commits Git est incohérent, comment repartir à zéro ?
Pour une fonctionnalité importante, il est courant d'avoir plusieurs corrections et révisions fréquemment validées. Au lieu de rebaser constamment la branche, vous pouvez retarder le nettoyage des commits jusqu'à la fin du développement.
C'est là que la création de fichiers patch s’avère très utile. En fait, les fichiers patch étaient le moyen principal de partager du code par e-mail lors de la collaboration sur de grands projets open source avant que des services basés sur Git comme GitLab ne soient disponibles pour les développeurs et les développeuses.
Imaginez que vous avez une branche (par exemple add-page-navigation
) où il y a des tonnes de commits qui ne transmettent pas clairement les changements sous-jacents. Voici comment vous pouvez créer un fichier patch pour tous les changements apportés dans cette branche :
-
La première étape pour créer ce fichier patch est de s’assurer que votre branche possède bien tous les changements présents dans la branche
master
et n’a pas de conflits avec celle-ci. -
Vous pouvez exécuter
git rebase master
ougit merge master
pendant que vous êtes dans la brancheadd-page-navigation
pour obtenir tous les changements de la branche master sur votre branche. -
Maintenant, créez le fichier patch. Pour ce faire, exécutez
git diff master add-page-navigation > ~/add_page_navigation.patch
.- Explication de la commande : nous utilisons la fonctionnalité diff de Git. Nous demandons une diff entre la branche
master
et la brancheadd-page-navigation
. Nous redirigeons le résultat (via le symbole>
) vers un fichier nomméadd_page_navigation.patch
dans notre répertoire personnel (typiquement~/
dans les systèmes d'exploitation *nix).
- Explication de la commande : nous utilisons la fonctionnalité diff de Git. Nous demandons une diff entre la branche
-
Vous pouvez spécifier n'importe quel chemin où vous souhaitez conserver ce fichier et choisir le nom et l’extension de ce fichier selon vos envies.
-
Une fois que la commande est exécutée et que vous ne voyez aucune erreur, votre fichier patch a bien été généré.
-
Maintenant, vérifiez la branche
master
. Exécutezgit checkout master
. -
Supprimez la branche
add-page-navigation
du dépôt local. Exécutezgit branch -D add-page-navigation
. Souvenez-vous que nous avons déjà effectué les modifications sur cette branche avec la création d’un fichier patch. -
Créez une nouvelle branche avec le même nom (pendant que la branche
master
est sélectionnée). Exécutezgit checkout -b add-page-navigation
. -
À ce stade, c'est une nouvelle branche qui n'a aucun de vos changements.
-
Enfin, appliquez vos changements à partir du fichier patch
git apply ~/add_page_navigation.patch
. -
Tous vos changements sont appliqués dans une branche et ils apparaîtront comme non validés, comme si toutes vos modifications avaient été faites, mais aucune d’entre elles n'avait été validées dans la branche.
-
Vous pouvez maintenant valider des fichiers individuels ou des fichiers groupés par zone d'impact dans l'ordre que vous souhaitez, avec de courts messages de commit.
Comme dans les situations précédentes, nous avons essentiellement modifié toute la branche. Il est donc temps de la pousser de force.
Conclusion sur l'historique des commits Git
Bien que nous ayons couvert la plupart des situations qui surviennent dans un workflow avec Git, la réécriture de l’historique Git reste un vaste sujet. Au fur et à mesure que vous vous familiarisez avec les astuces mentionnées ci-dessus, vous pourrez apprendre des concepts plus avancés sur ce sujet dans la documentation officielle de Git.
Photo par pan xiaozhen sur Unsplash.