Fermer

mai 10, 2022

Comprendre et travailler avec les sous-modules dans Git

Comprendre et travailler avec les sous-modules dans Git


La plupart des projets logiciels modernes dépendent du travail des autres. Ce serait une perte de temps de réinventer la roue dans votre propre code alors que quelqu’un d’autre a déjà écrit une merveilleuse solution. C’est pourquoi tant de projets utilisent du code tiers sous forme de bibliothèques ou de modules.

Git, le système de contrôle de version le plus populaire au monde, offre un excellent moyen de gérer ces dépendances de manière élégante et robuste. Son concept de « sous-module » nous permet d’inclure et de gérer des bibliothèques tierces tout en les séparant clairement de notre propre code.

Dans cet article, vous apprendrez pourquoi les sous-modules de Git sont si utiles, ce qu’ils sont réellement et comment ils fonctionnent.

Garder le code séparé

Pour bien comprendre pourquoi les sous-modules de Git sont en effet une structure inestimable, examinons un cas sans pour autant sous-modules. Lorsque vous avez besoin d’inclure du code tiers (comme une bibliothèque open source), vous pouvez bien sûr opter pour la solution de facilité : téléchargez simplement le code depuis GitHub et déposez-le quelque part dans votre projet. Alors que certainement rapidecette approche est certainement sale pour plusieurs raisons :

  • En copiant par force brute du code tiers dans votre projet, vous mélangez efficacement plusieurs projets en un seul. La frontière entre votre propre projet et celui de quelqu’un d’autre (la bibliothèque) commence à devenir floue.
  • Chaque fois que vous avez besoin de mettre à jour le code de la bibliothèque (parce que son responsable a fourni une nouvelle fonctionnalité intéressante ou corrigé un bogue désagréable), vous devez à nouveau télécharger, copier et coller. Cela devient rapidement un processus fastidieux.

La règle générale dans le développement de logiciels de « garder les choses séparées séparées » existe pour une raison. Et c’est certainement vrai pour la gestion du code tiers dans vos propres projets. Heureusement, le concept de sous-module de Git a été conçu exactement pour ces situations.

Mais bien sûr, les sous-modules ne sont pas la seule solution disponible pour ce genre de problème. Vous pouvez également utiliser l’un des différents systèmes de « gestionnaire de packages » fournis par de nombreux langages et frameworks modernes. Et il n’y a rien de mal à cela !

Cependant, vous pourriez dire que l’architecture des sous-modules de Git présente quelques avantages :

  • Les sous-modules fournissent une interface cohérente et fiable, quel que soit le langage ou le framework que vous utilisez. Surtout si vous travaillez avec plusieurs technologies, chacune peut avoir son propre gestionnaire de packages avec son propre ensemble de règles et de commandes. Les sous-modules, en revanche, fonctionnent toujours de la même manière.
  • Tous les morceaux de code ne sont peut-être pas disponibles via un gestionnaire de packages. Peut-être souhaitez-vous simplement partager votre propre code entre deux projets – une situation où les sous-modules peuvent offrir le flux de travail le plus simple possible.

Que sont vraiment les sous-modules Git

Les sous-modules dans Git ne sont en réalité que des référentiels Git standard. Pas d’innovation fantaisiste, juste les mêmes référentiels Git que nous connaissons tous si bien maintenant. Cela fait aussi partie de la puissance des sous-modules : ils sont si robustes et simples parce qu’ils sont si « ennuyeux » (d’un point de vue technologique) et testés sur le terrain.

La seule chose qui fait d’un dépôt Git un sous-module est qu’il est placé à l’intérieur une autre, parent Référentiel Git.

En dehors de cela, un sous-module Git reste un référentiel entièrement fonctionnel : vous pouvez effectuer toutes les actions que vous connaissez déjà de votre travail Git « normal » – de la modification de fichiers à la validation, l’extraction et la transmission. Tout est possible dans un sous-module.

Ajout d’un sous-module

Prenons l’exemple classique et disons que nous aimerions ajouter une bibliothèque tierce à notre projet. Avant d’aller chercher du code, il est logique de créer un dossier séparé où des choses comme celles-ci peuvent avoir une maison :

$ mkdir lib
$ cd lib

Nous sommes maintenant prêts à injecter du code tiers dans notre projet, mais de manière ordonnée, en utilisant des sous-modules. Disons que nous avons besoin d’une petite bibliothèque JavaScript « convertisseur de fuseau horaire »:

$ git submodule add https://github.com/spencermountain/spacetime.git

Lorsque nous exécutons cette commande, Git commence à cloner le référentiel dans notre projet, en tant que sous-module :

Cloning into 'carparts-website/lib/spacetime'...
remote: Enumerating objects: 7768, done.
remote: Counting objects: 100% (1066/1066), done.
remote: Compressing objects: 100% (445/445), done.
remote: Total 7768 (delta 615), reused 975 (delta 588), pack-reused 6702
Receiving objects: 100% (7768/7768), 4.02 MiB | 7.78 MiB/s, done.
Resolving deltas: 100% (5159/5159), done.

Et si nous jetons un coup d’œil à notre dossier de copie de travail, nous pouvons voir que les fichiers de la bibliothèque sont en fait arrivés dans notre projet.

Nos fichiers de bibliothèque sont ici, inclus dans un sous-module

« Alors, quelle est la différence ? » vous pourriez demander. Après tout, les fichiers de la bibliothèque tierce sont ici, comme ils le seraient si nous les avions copiés-collés. La différence cruciale est en effet qu’ils sont contenu dans leur propre référentiel Git! Si nous venions de télécharger des fichiers, de les jeter dans notre projet, puis de les valider – comme les autres fichiers de notre projet – ils auraient fait partie du même référentiel Git. Le sous-module, cependant, s’assure que les fichiers de la bibliothèque ne «fuient» pas dans le référentiel de notre projet principal.

Voyons ce qui s’est passé d’autre : un nouveau .gitmodules Le fichier a été créé dans le dossier racine de notre projet principal. Voici ce qu’il contient :

[submodule "lib/spacetime"]
  path = lib/spacetime
  url = https://github.com/spencermountain/spacetime.git

Cette .gitmodules Le fichier est l’un des multiples endroits où Git garde une trace des sous-modules de notre projet. Un autre est .git/configqui se termine maintenant comme ceci :

[submodule "lib/spacetime"]
  url = https://github.com/spencermountain/spacetime.git
  active = true

Et enfin, Git conserve également une copie de chaque sous-module .git référentiel dans un interne .git/modules dossier.

Ce sont tous des détails techniques dont vous n’avez pas besoin de vous souvenir. Cependant, cela vous aide probablement à comprendre que la maintenance interne des sous-modules Git est assez complexe. C’est pourquoi il est important de retenir une chose : ne plaisante pas avec la configuration du sous-module Git à la main ! Si vous souhaitez déplacer, supprimer ou manipuler un sous-module, faites-vous une faveur et faites ne pas essayez ceci manuellement. Utilisez les commandes Git appropriées ou un interface graphique de bureau pour Git comme « Tower »qui s’occupe de ces détails pour vous.

Les interfaces graphiques de bureau Git telles que Tower facilitent la gestion des sous-modules Git

Jetons un coup d’œil à l’état de notre projet principal, maintenant que nous avons ajouté le sous-module :

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
  new file:   .gitmodules
  new file:   lib/spacetime

Comme vous pouvez le voir, Git considère l’ajout d’un sous-module comme un changement comme un autre. En conséquence, nous devons valider ce changement comme n’importe quel autre :

$ git commit -m "Add timezone converter library as a submodule"

Cloner un projet avec des sous-modules Git

Dans notre exemple ci-dessus, nous avons ajouté un nouveau sous-module à un référentiel Git existant. Mais qu’en est-il de « l’inverse », lorsque vous clonez un référentiel qui contient déjà sous-modules ?

Si nous faisions une vanille git clone <remote-URL> sur la ligne de commande, nous téléchargerions le projet principal — mais nous trouverions tout dossier de sous-module vide ! Ceci est encore une preuve éclatante que les fichiers de sous-module sont séparés et ne pas inclus dans leurs référentiels parents.

Dans un tel cas, pour remplir les sous-modules après avoir cloné leur référentiel parent, vous pouvez simplement exécuter git submodule update --init --recursive ensuite. La meilleure façon est d’ajouter simplement le --recurse-submodules option dès que vous appelez git clone en premier lieu.

Vérification des révisions

Dans un référentiel Git « normal », nous vérifions généralement les branches. En utilisant git checkout <branchname> ou le plus récent git switch <branchname>, nous disons à Git ce que devrait être notre branche actuellement active. Lorsque de nouveaux commits sont faits sur cette branche, le pointeur HEAD est déplacé automatiquement au tout dernier commit. Ceci est important à comprendre, car les sous-modules Git fonctionnent différemment !

Dans un sous-module, nous vérifions toujours une révision spécifique — pas une branche ! Même lorsque vous exécutez une commande comme git checkout main dans un sous-module, en arrière-plan, la dernière commettre sur cette branche est noté – pas la branche elle-même.

Ce comportement, bien sûr, n’est pas une erreur. Pensez-y : lorsque vous incluez une bibliothèque tierce, vous souhaitez avoir un contrôle total sur le code exact utilisé dans votre projet principal. Lorsque le mainteneur de la bibliothèque publie une nouvelle version, c’est bien beau… mais vous ne voulez pas nécessairement que cette nouvelle version soit automatiquement utilisé dans votre projet. Tout simplement parce que vous ne savez pas si ces nouveaux changements pourraient casser ton projet!

Si vous voulez savoir quelle révision vos sous-modules utilisent, vous pouvez demander ces informations dans votre projet principal :

$ git submodule status
   ea703a7d557efd90ccae894db96368d750be93b6 lib/spacetime (6.16.3)

Cela renvoie la révision actuellement extraite de notre lib/spacetime sous-module. Et cela nous permet également de savoir que cette révision est une balise, nommée « 6.16.3 ». Il est assez courant d’utiliser beaucoup de balises lorsque vous travaillez avec des sous-modules dans Git.

Disons que vous vouliez que votre sous-module utilise un plus âgée version, qui a été étiqueté « 6.14.0 ». Tout d’abord, nous devons changer de répertoire pour que notre commande Git soit exécutée dans le contexte du sous-module, et non de notre projet principal. Ensuite, nous pouvons simplement exécuter git checkout avec le nom de la balise :

$ cd lib/spacetime/
$ git checkout 6.14.0
Previous HEAD position was ea703a7 Merge pull request 
HEAD is now at 7f78d50 Merge pull request 

Si nous revenons maintenant à notre projet principal et exécutons git submodule status encore une fois, nous verrons notre paiement reflété :

$ cd ../..
$ git submodule status
+7f78d50156ae1205aa50675ddede81a61a45fade lib/spacetime (6.14.0)

Examinez cependant de près la sortie : le petit + Le symbole devant ce hachage SHA-1 nous indique que le sous-module est à une révision différente de celle actuellement stockée dans le référentiel parent. Comme nous venons de modifier la révision extraite, cela semble correct.

Appel git status dans notre projet principal nous informe également de ce fait :

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
  modified:   lib/spacetime (new commits)

Vous pouvez voir que Git considère le déplacement du pointeur d’un sous-module comme un changement comme un autre : nous devons le valider dans le référentiel si nous voulons qu’il soit stocké :

$ git commit -m "Changed checked out revision in submodule"
$ git push

Mettre à jour un sous-module Git

Dans les étapes ci-dessus, il était nous qui a déplacé le pointeur de sous-module : c’est nous qui avons choisi d’extraire une révision différente, de la valider et de la pousser vers le référentiel distant de notre équipe. Mais que se passerait-il si l’un de nos collègues modifiait la révision du sous-module — peut-être parce qu’une nouvelle version intéressante du sous-module a été publiée et que notre collègue a décidé de l’utiliser dans notre projet (après des tests approfondis, bien sûr…).

Faisons un simple git pull dans notre projet principal – comme nous le ferions probablement assez souvent de toute façon – pour obtenir de nouvelles modifications à partir du référentiel distant partagé :

$ git pull
From https://github.com/gntr/git-crash-course
   d86f6e0..055333e  main       -> origin/main
Updating d86f6e0..055333e
Fast-forward
   lib/spacetime | 2 +-
   1 file changed, 1 insertion(+), 1 deletion(-)

L’avant-dernière ligne indique que quelque chose dans notre sous-module a été modifié. Mais regardons de plus près :

$ git submodule status
+7f78d50156ae1205aa50675ddede81a61a45fade lib/spacetime (6.14.0)

Je suis sûr que tu te souviens de ce petit + signe : cela signifie que le pointeur de sous-module a été déplacé ! Pour mettre à jour notre révision vérifiée localement vers la révision « officielle » que notre coéquipier a choisie, nous pouvons exécuter le update commande:

$ git submodule update lib/spacetime 
Submodule path 'lib/spacetime': checked out '5e3d70a88180879ae0222b6929551c41c3e5309e'

Très bien! Notre sous-module est maintenant extrait à la révision enregistrée dans notre référentiel de projet principal !

Travailler avec des sous-modules dans Git

Nous avons couvert les éléments de base de l’utilisation des sous-modules Git. Les autres flux de travail sont vraiment assez standard !

Vérification des nouveaux changements dans un sous-module, par exemple, fonctionne comme dans n’importe quel autre dépôt Git : vous exécutez un git fetch commande à l’intérieur du référentiel de sous-modules, éventuellement suivie de quelque chose comme git pull origin main si vous souhaitez effectivement utiliser les mises à jour.

Faire des changements dans un sous-module peut également être un cas d’utilisation pour vous, surtout si vous gérez vous-même le code de la bibliothèque (car il s’agit d’une bibliothèque interne, et non d’un tiers). Vous pouvez travailler avec le sous-module comme avec n’importe quel autre référentiel Git : vous pouvez apporter des modifications, les valider, les pousser, etc.

Utiliser toute la puissance de Git

Git a beaucoup de pouvoir sous le capot. Mais bon nombre de ses outils avancés – comme les sous-modules Git – ne sont pas bien connus. C’est vraiment dommage que tant de développeurs passent à côté de beaucoup de choses puissantes !

Si vous voulez aller plus loin et avoir un aperçu d’autres techniques Git avancéesje recommande vivement le « Kit Git avancé“ : c’est une collection (gratuite !) De courtes vidéos qui vous présentent des sujets tels que le Reflog, le Rebase interactif, le Cherry-Picking et même les stratégies de branchement.

Amusez-vous à devenir un meilleur développeur !




Source link