Git et dépendances de projet
NICOLA PAOLUCCI
Expert en développement
Réfléchissons aux questions suivantes :
Comment gérer les dépendances du projet avec Git
?
Notre projet est composé de plusieurs dépôts interdépendants. Actuellement, nous les gérons avec svn:externals
. Quel est le meilleur moyen de les gérer avec Git
?
Comment scinder un très gros dépôt en composants plus petits à l'aide de Git
?
Voici quelques-unes des questions les plus fréquentes.
Le sujet est un réel problème pour de nombreuses équipes de développement ayant adopté Git
. Par conséquent, cet article vise à faire la lumière sur ce point.
Manifestement, les dépendances de projet et les infrastructures de builds sont deux sujets étroitement liés. Nous avons d'ailleurs entamé un grand débat chez Atlassian concernant « l'avenir des builds ».
Le fait d'avoir des dépôts séparés au lieu d'un dépôt unique peut compliquer les choses. C'est toutefois une étape relativement naturelle (et parfois obligatoire) dans l'évolution d'un projet de logiciel pour au moins deux raisons essentielles : améliorer les temps de build et avoir des dépendances partagées entre les projets.
Généralités : Directives et solutions non optimales
Revenons-en à nos moutons : Comment suivre et gérer les dépendances de projet avec Git
?
Si possible, ne le faites pas !
Blague à part, je vais d'abord vous donner quelques informations générales, puis j'entrerai dans les détails. Sachez qu'il n'existe pas de solution magique (que ce soit dans Git
ou ailleurs) qui résoudra tous les problèmes liés aux dépendances de projet.
Une fois qu'un projet a atteint un certain volume, il est recommandé de le diviser en plusieurs composants logiques, mais n'attendez pas d'avoir 100 millions de lignes de code supplémentaires dans un seul dépôt avant de le faire. Les conseils qui suivent vous aideront à trouver la bonne approche.
Ressource connexe
Installation de Git
DÉCOUVRIR LA SOLUTION
Découvrir Git avec Bitbucket Cloud
Premier choix : utiliser un outil de gestion des dépendances/builds approprié plutôt que Git
Je recommande d'utiliser un outil de gestion des dépendances pour gérer les difficultés croissantes et les temps de build des projets volumineux.
Conservez vos modules séparément dans des dépôts individuels et gérez leur interdépendance à l'aide d'un outil spécifique. Il en existe un pour (presque) toutes les technologies. Quelques exemples :
- Maven (ou Gradle) si vous utilisez Java
- Npm pour les applications Node
- Bower, Component.io, etc. si vous utilisez Javascript (mis à jour !)
- Pip et les fichiers requirements.txt si vous utilisez Python
- RubyGems et Bundler si vous utilisez Ruby
- NuGet pour .NET
- Ivy (ou certaines actions personnalisées sur CMake) pour C++ (mis à jour !)
- CocoaPods pour les applications Cocoa sous iOS
- Composer ou Phing pour PHP (ajouté !)
- Dans Go, l'infrastructure de builds/dépendances est d'une certaine manière intégrée au langage (même si certains développeurs travaillent sur une solution plus complète, voir godep). Pour notre serveur Git (Bitbucket), nous utilisons Maven et Bower. Au moment du build, l'outil choisi fera un pull des bonnes versions des dépendances, et vous pourrez ainsi développer votre projet main. Si certains de ces outils ont des limites et que leurs hypothèses ne sont pas toujours optimales, ils ont fait leurs preuves et sont viables.
Diviser un projet, quelle corvée !
En résumé, au début d'un projet, tous les éléments sont contenus dans un build. Plus le projet évolue, plus le build risque de perdre de la vitesse, d'où l'intérêt d'effectuer une mise en cache afin de gérer les dépendances. Cela signifie par ailleurs que les submodules (voir ci-dessous) se prêtent particulièrement bien aux langages dynamiques, par exemple. Je pense que dans la plupart des cas, les temps de build peuvent devenir préoccupants à un moment ou un autre, c'est pourquoi vous devez utiliser un outil de gestion des dépendances.
Répartir les composants dans des dépôts séparés présente des inconvénients. En voici quelques-uns :
- Modifier un composant nécessite une livraison
- Perte de temps et échec possible pour des tas de raisons débiles
- Pas nécessaire en cas de changements mineurs
- Il faut configurer manuellement les nouveaux builds pour chaque composant.
- Entrave la détectabilité des dépôts
- Refactoring nécessaire lorsque le code source n'est pas entièrement disponible dans un dépôt unique
- Dans certaines configurations (comme la nôtre), la mise à jour des API nécessite une livraison pilote du produit, puis du plug-in et à nouveau du produit. Nous avons probablement oublié quelque chose, mais vous comprenez où nous voulons en venir. C'est loin d'être la panacée.
Deuxième option : Utiliser git submodule
Si vous ne pouvez ou ne voulez pas utiliser un outil de gestion des dépendances, Git
comporte une fonctionnalité pour gérer les submodules
. Les submodules peuvent s'avérer pratiques, surtout pour les langages dynamiques. Cependant, ils n'amélioreront pas forcément les temps de build. J'ai déjà rédigé quelques consignes et astuces les concernant, et j'ai aussi exploré quelques solutions alternatives. La plupart des internautes avancent des arguments opposés.
1:1 match between svn:external and git
ATTENTION ! Si vous cherchez une correspondance parfaite entre svn:externals
et git,
, vous utiliserez volontiers submodules
pour veiller à ce que les submodules
(sous-modules) suivent uniquement des branches de livraison, et non des commits aléatoires.
Troisième choix : utiliser d'autres outils de build et de gestion des dépendances cross-stack
Vous n'aurez pas toujours la chance de travailler sur un projet complètement uniforme, que vous pouvez développer et assembler au moyen d'un seul outil. Par exemple, pour certains projets mobiles, il vous faudra jongler entre des dépendances développées en Java et en C++, ou utiliser des outils propriétaires pour créer des actifs. Dans ces situations plus complexes, vous pouvez enrichir Git
d'une couche supplémentaire sur le dessus. Un bel exemple du genre est le dépôt Android.
Autres outils de build qui valent la peine d'être examinés :
Conclusion et publications à consulter
Suggestions de lecture de Charles O'Farrell pour en savoir plus sur le thème de l'infrastructure de build (et sur Maven) :
- À la recherche de l'outil de build idéal
- Et la suite, Maven is broken by design.
- Recursive Maven considered harmful
Je souhaiterais maintenant conclure avec une excellente citation extraite de ce dernier article. Même si elle fait référence à Maven, elle s'applique aussi à d'autres outils de gestion des builds et des dépendances.
« Un cache se contente d'accélérer les choses. Vous pourriez supprimer un cache intégralement et le système environnant fonctionnerait de la même manière, mais moins vite. Un cache n'a aucun effet secondaire. Peu importe ce que vous avez fait avec un cache par le passé, une requête spécifique sur le cache renverra exactement la même valeur que la même requête soumise ultérieurement.
L'expérience Maven est très différente de ma description ! Les dépôts Maven sont utilisés comme des caches, mais ils n'en possèdent pas les propriétés. Lorsque vous souhaitez récupérer des éléments dans un dépôt Maven, les opérations réalisées précédemment sont très importantes. Le dépôt renvoie l'élément ajouté le plus récemment. Il peut même échouer si vous voulez récupérer un élément avant de l'y ajouter. »
Partager cet article
Thème suivant
Lectures recommandées
Ajoutez ces ressources à vos favoris pour en savoir plus sur les types d'équipes DevOps, ou pour les mises à jour continues de DevOps chez Atlassian.