Git : suivre et automatiser son application

Quand nous parlons d'automatisation, nous ne pouvons faire autrement que de passer par la case Git, « le » système pour versionner nos projets. Mais comment bien l'employer ?
Git : suivre et automatiser son application

Dans un monde où l’IA nous permet de générer du code à une vitesse fulgurante, le risque de perdre le fil de nos modifications ou de casser une fonctionnalité qui marchait « juste avant » est démultiplié.

Git n’est pas seulement un outil de sauvegarde ; c’est le cœur battant de notre usine logicielle. Nous nous proposons dans cet article d’explorer la philosophie derrière cet outil, comment l’utiliser au quotidien pour sécuriser notre travail et surtout, comment il devient le levier indispensable de nos déploiements automatisés.

Nous explorerons ses fondamentaux, sa pratique quotidienne et son rôle pivot dans la CI/CD.

Les fondamentaux théoriques : comprendre la machine

Pour bien utiliser Git, nous devons comprendre qu’il ne raisonne pas comme les anciens systèmes. Là où ses prédécesseurs stockent une liste de changements apportés aux fichiers (les différences) Git, lui, prend des photos instantanées de notre projet à un instant T, ou des snapshots.

L’historique local

Contrairement aux systèmes centralisés, chaque développeur possède sur sa machine l’intégralité de l’historique et des versions du projet. Notre clone est une sauvegarde complète. Cette approche permet de rendre Git plus performant que ses prédécesseurs, notamment pour les fonctionnalités que nous allons voir ci-dessous.

Le système de branches

C’est la « killer feature » de Git. Une branche est un pointeur léger vers un commit. Cela nous permet de paralléliser le travail : nous créons une branche pour chaque nouvelle fonctionnalité sans polluer le code stable.

Ainsi, si nous introduisons des bugs ou des régressions avec nos modifications, ceux-ci sont isolés de la branche principale, servant à construire la version de production, et nous pouvons réparer tranquillement nos erreurs avant d’ajouter de nouvelles fonctionnalités (ou, dans le pire des cas, abandonner toutes les modifications sans conséquence sur l’existant).

La souplesse des tags

Ils servent de marque-pages immuables consistant en une chaîne de caractères libres (chiffres, lettres et tirets) permettant de représenter à peu près n’importe quelle information pertinente pour le développeur.

Nous les utilisons généralement pour identifier les versions de nos projets. Par exemple, nous créerons un tag v1.0.1 permettant de comprendre que le commit ainsi tagué contient une version validée de notre produit, avec un certain nombre de fonctionnalités, correctifs, etc.

Nous avions déjà eu l’occasion de parler du système de version (ici SemVer) et d’autres bonnes pratiques pertinentes avec Git, dans notre article sur le produit prêt pour l’ère de l’IA. Toutes ces recommandations fonctionnent également sur Git.

Git au quotidien : garder le contrôle

Maîtriser Git, c’est savoir répondre à deux questions : « Qu’ai-je modifié ? » et « Pourquoi l’ai-je fait ? ».

Contrôler ses modifications : Avant de valider (committer) notre travail, nous utilisons systématiquement git diff. Cette commande montre précisément les lignes ajoutées ou supprimées, évitant ainsi d’envoyer du code de debug par erreur, des informations sensibles, ou du code mal structuré.

L’archéologie du code

La commande git log est notre carnet de bord. Elle permet de parcourir l’historique du projet pour comprendre qui a introduit quel changement et dans quel but.

Lorsqu’elle est bien configurée, cette commande permet de bien distinguer quelle branche – et donc quel travail – a apporté quelle modification sur le produit.

Je me suis par exemple créé deux alias de git log permettant de retrouver l’essentiel de l’information de façon condensée :

alias gl="git log --graph --pretty=format:'%Cred%h%Creset - %C(yellow)%d %Cgreen(%ad - %cr) %C(bold blue)<%an>%Creset %s' --abbrev-commit --name-status"
alias glg="git log --oneline --graph --pretty=format:'%Cred%h%Creset - %C(yellow)%d %Cgreen(%cr) %C(bold blue)<%an>%Creset %<(50,trunc)%s'"

Par exemple :

  • « oneline » informe git log de fournir l’information d’un commit donné sur une seule ligne ;
  • « graph » introduit l’affichage d’une représentation graphique des branches, avec les fusions, etc. sur le côté du terminal ;
  • «pretty» utilise une syntaxe pouvant paraître un peu barbare au premier abord, mais qui permet d’exprimer une mise en forme du texte (avec des couleurs, etc.) ;

Le dernier alias glg pourrait donner une réponse du style suivant :

* 8bc20f3 -  (HEAD -> main, origin/main, origin/HEAD) (2 days ago) <GitHub Copilot> docs(readme): finalize validated local setup and ..
* 947255e -  (2 days ago) <GitHub Copilot> feat(devops): add local bootstrap, deployment ..
[...]
* 8b33839 -  (2 days ago) <GitHub Copilot> feat(frontend): implement functional React app ..

Nous pouvons remarquer au passage que les messages que nous fournissons lors des commits peuvent être récupérés avec git log. Cela souligne l’importance des messages de commit pertinents, car lorsque l’historique s’accumule, ce peut être la seule information sous la main (avec la liste des fichiers modifiés et l’auteur des modifications) qui nous permet de comprendre ce qui a été fait, et ainsi retrouver un indice sur l’endroit où chercher l’origine d’un problème donné.

Le Cherry-pick

Parfois, nous ne voulons pas fusionner toute une branche de développement, mais juste récupérer un correctif spécifique. Le cas d’usage le plus courant que j’ai vu concerne un correctif appliqué sur la nouvelle version, encore en cours de développement, mais que nous souhaitons ajouter à la version du produit déjà en production (souvent pour un bug majeur et bloquant pour les utilisateurs).

C’est exactement le rôle de cherry-pick. Au lieu de fusionner toute la branche (ce qui mélangerait du contenu de la nouvelle version avec l’ancienne), cette commande nous permet de cibler un ensemble très précis de commits pour les dupliquer proprement sur notre branche cible.

C’est l’outil idéal pour nous permettre de récupérer rapidement un correctif urgent ou une fonctionnalité isolée développée ailleurs. Il nous évite d’importer tout l’historique ou les bugs potentiels liés aux autres modifications de la branche. Son usage requiert cependant une grande rigueur, pour éviter la création de doublons de commits, ou des conflits (s’il y a trop de divergences de code là où nous insérons les commits).

Pour cela, nous sélectionnons la branche cible, puis nous listons les commits à prendre, et il ne reste plus qu’à valider leur intégration. L’exercice doit être appliqué de façon très rigoureuse, et chaque commit doit contenir exclusivement des modifications spécifiques à notre correctif (là aussi, les messages des commits sont d’une grande aide).

Les interfaces de collaboration : GitHub et GitLab

Si Git gère les versions sur notre machine, des plateformes comme GitHub et GitLab permettent de centraliser ce code et de collaborer efficacement.

C’est ici qu’intervient la notion de Pull Request (PR) de GitHub, ou de Merge Request (MR) de Gitlab. La différence de nom reflète une différence de philosophie, mais les deux fonctionnent à peu près de la même façon. Dans les deux cas, nous isolons notre code sur une branche, nous demandons à d’autres membres de l’équipe de le relire, puis nous l’intégrons dans la branche principale. C’est donc un espace de discussion autour des changements de code. Si nous utilisons l’IA, nous pouvons en profiter pour relire les modifications qu’elle soumet pour suggérer des changements, puis valider le tout une fois satisfaits.

Concernant la petite nuance de philosophie, GitHub reprend la logique du développement open source, où le développeur propose une modification au mainteneur du projet (on va tirer – « pull » – les modifications vers le dépôt), tandis que sur Gitlab, nous avons plutôt une logique d’entreprise, focalisée sur la gouvernance, où le développeur demande l’autorisation de fusionner (« merge ») ses modifications avec le code du dépôt.

Dans les deux cas, nous pouvons ainsi contrôler la qualité des modifications apportées au projet, autant en tant qu’humains contrôlant le travail de notre IA, qu’au moyen des agents IA embarqués dans la validation de la requête (grâce à des outils spécifiques que GitHub et Gitlab proposent).

La CI/CD : le « Git push to deploy »

C’est ici que la magie de l’automatisation opère. En connectant notre dépôt Git à un système de CI/CD (GitLab CI ou GitHub Actions), chaque push peut déclencher une série d’actions automatiques, selon des pipelines de CI.

J’ai déjà eu l’occasion d’explorer en détail le rôle et le fonctionnement de ces processus automatisé au travers de trois articles :

Enfin, des outils comme Ansible ou Terraform peuvent être pilotés par notre pipeline pour mettre à jour nos serveurs ou provisionner de nouvelles ressources dans le Cloud.

Terraform sert à instrumenter une infrastructure, ce que nous appelons également l’Infrastructure as Code (ou IaC). Typiquement, la plupart des fournisseurs de services Cloud (comme AWS, Azure, etc.) proposent des « providers », ou extensions, permettant de manipuler directement les ressources du Cloud via Terraform. Nous pouvons ainsi déclencher la création d’une machine virtuelle, etc. Nous aurons l’occasion de développer tous ces concepts dans nos prochains articles. Ansible, de son côté, permet d’aller déployer notre application dans l’infrastructure par ailleurs pilotée par Terraform (ou manuellement, les deux outils sont indépendants).

Leur combinaison permet en tout cas d’atteindre le Graal de l’entrepreneur tech : modifier son code, faire un push et voir son application mise à jour en production sans intervention manuelle.

Conclusion

Git est bien plus qu’un simple outil technique ; c’est le garant de notre sérénité. En adoptant une stratégie de branche rigoureuse et en exploitant la puissance des pipelines de CI/CD, nous transformons un processus de livraison autrefois manuel et risqué en un flux continu et sécurisé.

À l’ère de l’IA, c’est l’assurance qu’elle reste un assistant productif sans devenir un facteur de chaos.

Ressources


Write a comment