Les outils de Git
Mettre de côté des modifications avec git stash
Il arrive régulièrement qu’un développeur soit dérangé pendant qu’il travaille sur une nouvelle fonctionnalité. C’est souvent en raison d’un e-mail débutant par le mot « URGENT » que le développeur doit stopper son développement pour corriger un bug éventuel.
Idéalement, le développeur ne doit pas commiter son développement pour corriger le bug. Ce commit serait alors composé de modifications non terminées, avec un code non fonctionnel et peut-être des lignes de débogage. Un commit ne doit être effectué que lorsque le projet a été testé et est fonctionnel, ce qui ne correspond pas à un travail en cours.
git stash peut avoir plusieurs utilités. Imaginons le cas d’un développeur qui souhaite faire une démonstration client (sans l’avoir prévue à l’avance). Le développeur était en plein développement et certaines pages retournent encore une page d’erreur. En utilisant git stash, le développeur remet son projet dans le même état qu’après son dernier commit tout en conservant son développement en cours pour une prochaine fois. Le développeur peut alors faire sa démonstration facilement...
Dépôts intégrés avec submodules
Aujourd’hui, dans un grand nombre de projets, les développeurs utilisent des bibliothèques. Par exemple, beaucoup de projets web intègrent désormais des bibliothèques comme jQuery, Bootstrap ou encore AngularJS. Ces bibliothèques sont nécessaires au fonctionnement du projet, il est donc important de les avoir dans le dépôt principal (à moins d’utiliser les services d’un CDN qui les héberge).
Le problème qui se pose lorsque les développeurs ajoutent les sources de la bibliothèque directement dans leur dépôt principal est que ces codes vont polluer les commits et les statistiques du dépôt avec du code qui n’a pas été créé par un développeur interne.
En effet, avec les sources directement présentes dans leur dépôt, à chaque mise à jour de la bibliothèque, les développeurs devront copier les nouveaux fichiers de la bibliothèque et faire un commit volumineux avec comme message "Mise à jour vers Bootstrap 3.3.0". Le dépôt contiendra donc des commits qui ne correspondront pas du tout au projet et qui ne seront pas le fruit du travail de l’équipe de développement. De plus, si des statistiques venaient à être effectuées sur le dépôt, les ajouts et mises à jour des bibliothèques les fausseraient.
Il existe des solutions à ce problème. La solution la plus adaptée est d’utiliser un système de gestion de dépendances versionné. Un tel système permettra de lister les bibliothèques dont les développeurs ont besoin et de spécifier la version utilisée dans le projet. Par exemple, dans un projet Python, l’outil de gestion de dépendances nommé PIP permet d’installer et de mettre à jour les bibliothèques. Une convention, lorsqu’on utilise PIP, est de créer un fichier requirements.txt à la racine du dépôt. Ce fichier contiendra la liste des dépendances utilisées dans le projet. Selon les conventions des autres technologies, le fichier de dépendances peut s’appeler différemment. Par exemple, sur des projets...
Retrouver un commit erroné
Dans tout type de développement, il arrive qu’à l’occasion du développement d’une fonctionnalité ou de la correction d’un bug, les modifications d’un développeur introduisent une régression dans son code : une autre partie du logiciel devient non fonctionnelle. Les régressions sont ajoutées sans que le développeur s’en rende compte, et si aucun test unitaire ou fonctionnel n’est fait pour détecter l’erreur, alors elle reste présente jusqu’à ce qu’un utilisateur ou un développeur détecte le problème.
Git aide le développeur à retrouver le commit qui a introduit la régression par une recherche dichotomique assistée par l’utilisateur. À chaque étape de git bisect, Git va remplacer le répertoire de travail par une ancienne version et il faut alors lui indiquer si l’erreur est toujours présente. Il va alors restreindre le nombre de commits qui sont susceptibles d’avoir ajouté l’erreur, puis il va effectuer une itération en modifiant à nouveau le répertoire de travail.
Une recherche dichotomique est un algorithme de recherche qui consiste à couper une plage de valeurs en deux parties égales à chaque étape. À la fin de chaque étape, on ne garde qu’une moitié comme plage de solutions acceptables, puis on effectue une nouvelle étape pour réduire la plage de solutions.
1. Utilisation pratique...
Journal des références (reflog)
Avant de parler du journal des références, il est utile de rappeler que HEAD est une référence (c’est-à-dire un pointeur) qui pointe vers le commit le plus récent de la branche courante.
Il existe dans Git un journal de toutes les références prises par le pointeur HEAD : ce journal s’appelle le reflog (pour « log de référence »). C’est un journal qui va enregistrer tous les commits par lesquels passe ce pointeur. Le reflog va par exemple être capable d’enregistrer les changements de branche ou alors l’ajout de commit.
Pour visualiser ce journal, il faut utiliser la commande suivante :
git reflog
Utilisée sur le dépôt ayant servi aux tests de la section Retrouver un commit erroné, cette commande affiche la sortie suivante :
1f28629 HEAD@{0}: checkout: moving from
be902d9cc6cacfc7a927a8a07a5774a6aff6f0b4 to master
be902d9 HEAD@{1}: checkout: moving from d42018b585c7a5b6b3593031
faaefb09376bb14c to be902d9cc6cacfc7a927a8a07a5774a6aff6f0b4
d42018b HEAD@{2}: checkout: moving from
5b9094ff2f09fb74ec6c9965bdd02f6b6666ab88 to
d42018b585c7a5b6b3593031faaefb09376bb14c
... Sortie tronquée ...
d42018b HEAD@{21}: commit: LICENCE : ajout
2992238 HEAD@{22}: commit: README...Les hooks
Les hooks (ou « crochet » - le terme français étant moins utilisé) sont des scripts qui sont exécutés lors d’actions spécifiques sur le dépôt. Ils permettent d’automatiser certaines tâches récurrentes comme la minification de fichiers JavaScript, la vérification du message de commit ou encore l’exécution de tests automatisés.
1. Les différents types de hooks
Il existe deux familles de hooks :
-
les hooks côté serveur ;
-
les hooks côté client.
Les hooks côté serveur sont exécutés sur les dépôts distants. Ils permettent d’effectuer des actions telles que :
-
vérifier que l’utilisateur a le droit de pusher vers une branche ;
-
déployer une nouvelle version du projet.
Les hooks côté client sont exécutés sur les dépôts locaux et permettent d’effectuer des actions telles que :
-
minifier des fichiers JS/CSS après un changement de branche ;
-
vérifier la syntaxe des fichiers ;
-
lancer les tests automatisés.
Chaque hook est identifié par un nom qui définit le moment où Git l’exécutera.
Les hooks côté serveur sont les suivants :
-
pre-receive : ce hook est exécuté par le serveur au début de la réception d’un push. Il sert à vérifier que la politique de push est bien respectée (commit conforme aux bonnes pratiques, droit de push sur la branche, etc.). Le push peut être refusé si les conditions du hook ne sont pas remplies.
-
post-receive : ce hook est exécuté lorsque le push et l’intégration des commits ont été...
Les notes Git
Git propose un système permettant d’attribuer des commentaires à des commits. Ce système de notes ne remplace absolument pas le message de commit. Contrairement aux messages de commit, les notes Git ne modifient pas le commit. Les notes sont attachées à un commit sans le modifier. Cela permet par exemple d’ajouter des détails concernant un commit ou encore de suivre les revues de code d’un commit.
Dans une équipe utilisant Git-Flow, il est d’ailleurs tout à fait possible au dernier commit des branches hotfix d’ajouter une note avec un flag #readyToDeploy pour spécifier que le commit est prêt à être déployé. Ce type de flag n’aurait rien à faire dans un message de commit, car il ne pourrait pas être supprimé, alors que dans une note, il a sa place.
1. Créer une note
Pour créer une note attachée à un commit, il faut utiliser la commande suivante :
git notes add <commit>
Il est possible d’utiliser l’argument -m pour définir le message ou alors de laisser Git ouvrir l’éditeur de texte.
Une fois le message validé, Git crée un nouvel objet correspondant au message et l’attache au commit. Il faut rester vigilant lorsqu’on enregistre une note sur un commit à partir d’une référence dynamique. Une note enregistrée...
git worktree
git worktree est une fonctionnalité puissante et très pratique de Git qui permet de travailler simultanément sur plusieurs branches d’un même dépôt dans des répertoires différents, sans avoir à cloner plusieurs fois le dépôt. Chaque worktree prend la forme d’un répertoire indépendant lié au même dépôt Git, mais pointant vers une branche, un tag ou un commit spécifique. Cela signifie qu’il est possible de basculer entre différentes versions du code en ouvrant simplement un nouveau dossier, plutôt qu’en utilisant git checkout ou git switch dans un unique répertoire de travail.
1. Pourquoi utiliser git worktree ?
git worktree est apparu en 2017 dans la version 2.5.6. Avant que cette fonctionnalité ne soit ajoutée à Git, pour travailler sur des répertoires différents en fonction des branches, il fallait cloner le dépôt autant de fois qu’il était nécessaire.
git worktree permet donc de travailler sur plusieurs branches en parallèle : par exemple, reproduire et corriger un bug urgent sur master tout en développant une nouvelle fonctionnalité sur une branche (feature).
git worktree fait par exemple gagner beaucoup de temps lors de la mise à jour d’un framework tel que Django. Il est alors possible...
Les patchs Git
Les patchs sont des ensembles de modifications qu’il est possible de transmettre en passant par des fichiers totalement externes au dépôt. L’envoi se fait par e-mail ou par n’importe quel moyen permettant d’envoyer du texte et d’en préserver la syntaxe.
Il existe deux façons de générer des patchs : les patchs bruts, ou patchs de différence, et les patchs formatés basés sur les commits.
1. Les patchs bruts ou patchs de différence
Ce genre de patch est très pratique pour transmettre rapidement une modification à un autre collaborateur du dépôt. Il se génère avec la commande git diff. Ce type de patch est dit « brut », car il ne contient que des modifications et aucune métadonnées concernant l’auteur ou le moment des modifications.
Pour créer un patch, il suffit de rediriger la sortie de git diff vers un fichier de cette façon :
git diff > diff.patch
Tous les arguments de la commande git diff sont utilisables, il est donc possible de limiter le diff par fichier ou de profiter de toutes les possibilités offertes par la commande git diff.
Pour appliquer le patch, il faut utiliser la commande suivante :
git apply diff.patch
Attention, cette commande va essayer d’appliquer les modifications dans le répertoire de travail. Des conflits peuvent survenir...
Labo Git : testez par vous-même
Comme vu au chapitre Manipulation des fichiers et commit, à la section Manipuler les fichiers/Déplacer ou renommer des fichiers, la commande git mv permet de déplacer ou de renommer des fichiers. Mais il n’est pas évident de se rendre compte de son intérêt.
La commande git mv est parfaite pour introduire la notion de labo Git. En effet, parfois il n’est pas évident de savoir de quelle façon Git va se comporter dans telle ou telle situation. Dans ce cas, il peut être utile de mettre en place une sorte de minilabo Git.
Le but de cette section est non seulement d’expliquer les effets de la commande git mv, mais également de décrire une méthode permettant de comparer deux situations. Ce qui peut être utile notamment lorsque vous ne savez pas comment Git va réagir à certaines commandes. Nous allons partir d’un dépôt vierge plutôt que travailler directement sur le dépôt d’un projet complet, la situation sera beaucoup moins complexe.
L’objectif ici est de comparer ce qui se produit lors de l’utilisation de git mv et lorsqu’on déplace un fichier sans passer par Git (et que son mécanisme de détection des déplacements échoue).
Il convient donc de mettre en place l’état initial commun aux deux situations testées, puis d’éprouver chacune d’entre elles.
1. Situation commune
Les actions suivantes permettent de mettre en place l’état initial attendu :
-
la création du dossier contenant le dépôt ;
-
l’initialisation du dépôt ;
-
la création d’un fichier GIT_USAGE.md.
mkdir repo_mv_follow
cd repo_mv_follow
git init
touch GIT_USAGE.md
Il convient ensuite d’éditer le fichier avec un contenu d’exemple comme celui-ci :
# Procédure Git
## Que faire en cas de conflit ?
Bien analyser la situation afin de le traiter sans erreur.
Une résolution de conflit bâclée pour être très coûteuse pour une équipe.
Il faut ensuite ajouter le fichier à l’index en vue de le commiter :
git add GIT_USAGE.md
git commit -m "GIT_USAGE : start"...