Nous faisons des projets, mais nous réutilisons beaucoup de code entre les projets et avons beaucoup de bibliothèques qui contiennent notre code commun. Au fur et à mesure que nous implémentons de nouveaux projets, nous trouvons plus de façons de factoriser le code commun et de le mettre dans les bibliothèques. Les bibliothèques dépendent les unes des autres et les projets dépendent des bibliothèques. Chaque projet et toutes les bibliothèques utilisées dans ce projet doivent utiliser la même version de toutes les bibliothèques auxquelles ils se réfèrent. Si nous publions un logiciel, nous devrons corriger des bugs et peut-être ajouter de nouvelles fonctionnalités pendant de nombreuses années, parfois pendant des décennies. Nous avons environ une douzaine de bibliothèques, les changements se répartissent souvent sur plus de deux et plusieurs équipes travaillent sur plusieurs projets en parallèle, apportant des modifications simultanées à toutes ces bibliothèques.
Nous avons récemment basculé vers git et mis en place des référentiels pour chaque bibliothèque et chaque projet. Nous utilisons stash comme référentiel commun, faisons de nouvelles choses sur les branches de fonctionnalités, puis faisons des demandes d'extraction et ne les fusionnons qu'après examen.
Bon nombre des problèmes que nous devons traiter dans les projets nous obligent à apporter des modifications à plusieurs bibliothèques et au code spécifique du projet. Il s'agit souvent de modifications des interfaces de bibliothèque, dont certaines sont incompatibles. (Si vous pensez que cela semble louche: nous nous connectons avec du matériel et cachons du matériel spécifique derrière des interfaces génériques. Presque chaque fois que nous intégrons du matériel d'un autre fournisseur, nous rencontrons des cas que nos interfaces actuelles n'anticipaient pas, et nous devons donc les affiner.) Pour exemple, imaginez un projet en P1
utilisant les bibliothèques L1
, L2
et L3
. L1
utilise également L2
et L3
, et L2
utilise L3
également. Le graphique des dépendances ressemble à ceci:
<-------L1<--+
P1 <----+ ^ |
<-+ | | |
| +--L2 |
| ^ |
| | |
+-----L3---+
Imaginez maintenant qu'une fonctionnalité de ce projet nécessite des modifications dans P1
et L3
qui modifient l'interface de L3
. Ajoutez maintenant des projets P2
et P3
dans le mix, qui font également référence à ces bibliothèques. Nous ne pouvons pas nous permettre de les passer tous à la nouvelle interface, d'exécuter tous les tests et de déployer le nouveau logiciel. Alors, quelle est l'alternative?
- implémenter la nouvelle interface dans
L3
- faire une demande d'extraction
L3
et attendre l'examen - fusionner le changement
- créer une nouvelle version de
L3
- commencer à travailler sur la fonctionnalité en la
P1
faisant référence àL3
la nouvelle version de, puis implémenter la fonctionnalité surP1
la branche de fonctionnalité de - faire une demande d'extraction, la faire examiner et fusionner
(Je viens de remarquer que j'ai oublié de passer L1
et L2
de la nouvelle version. Je ne sais même pas où coller cela dans, car il devrait être fait en parallèle avec P1
...)
Il s'agit d'un processus fastidieux, sujet aux erreurs et très long pour implémenter cette fonctionnalité, il nécessite des examens indépendants (ce qui le rend beaucoup plus difficile à examiner), ne se modifie pas du tout et est susceptible de nous mettre hors service parce que nous être tellement embourbé dans le processus que nous ne faisons rien.
Mais comment utiliser la ramification et le balisage afin de créer un processus qui nous permet d'implémenter de nouvelles fonctionnalités dans de nouveaux projets sans trop de frais généraux?
Réponses:
Sorte de l'évidence ici, mais ça vaut peut-être la peine de le mentionner.
Habituellement, les git repos sont personnalisés par lib / projet car ils ont tendance à être indépendants. Vous mettez à jour votre projet et ne vous souciez pas du reste. Les autres projets qui en dépendent mettront simplement à jour leur bibliothèque quand ils le jugeront bon.
Cependant, votre cas semble fortement dépendant des composants corrélés, de sorte qu'une caractéristique affecte généralement bon nombre d'entre eux. Et le tout doit être conditionné sous forme de bundle. Étant donné que la mise en œuvre d'une fonctionnalité / modification / bogue nécessite souvent d'adapter plusieurs bibliothèques / projets différents à la fois, il est peut-être judicieux de les mettre tous dans le même référentiel.
Il existe de forts avantages / inconvénients à cela.
Avantages:
Désavantages:
A vous de savoir si le prix en vaut la peine.
ÉDITER:
Cela fonctionnerait comme ceci:
feature_x
feature_y
etfeature_z
peut-être aussi ajouté. Cela devient une fusion "inter-équipes". C'est pourquoi c'est un sérieux inconvénient.juste pour mémoire: je pense que dans la plupart des cas, c'est une mauvaise idée et que cela doit être fait avec prudence car l'inconvénient de la fusion est généralement plus élevé que celui que vous obtenez grâce à la gestion des dépendances / au suivi des fonctionnalités.
la source
:-/
De plus, même ceux qui sont (et qui ont poussé à passer à git), ne savent pas comment adapter notre processus de développement à git. Soupir. Ça va être quelques mois difficiles, je le crains, jusqu'à ce que les choses commencent à s'améliorer. Merci de toute façon, la vôtre est la réponse la plus / seule utile à ce jour.La solution que vous recherchez est un outil de gestion des dépendances en coordination avec les sous-modules git
Des outils tels que:
Vous pouvez utiliser ces outils pour définir les dépendances d'un projet.
Vous pouvez exiger qu'un sous-module soit au moins version > 2.xx ou indiquer une gamme de versions qui sont compatibles = 2.2. * Ou moins qu'une version particulière <2.2.3
Chaque fois que vous publiez une nouvelle version de l'un des packages, vous pouvez la marquer avec le numéro de version, de cette façon, vous pouvez insérer cette version spécifique du code dans tous les autres projets
la source
Sous-modules
Vous devriez essayer de créer des sous - modules , comme suggéré dans un commentaire.
Lorsque le projet
P1
fait référence aux trois sousL1
- modules ,L2
etL3
, il stocke en fait une référence à des validations particulières dans les trois référentiels: ce sont les versions de travail de chaque bibliothèque pour ce projet .Ainsi, plusieurs projets peuvent fonctionner avec plusieurs sous-modules:
P1
peuvent faire référence à l'ancienne version de la bibliothèqueL1
tandis que le projetP2
utilise la nouvelle version.Que se passe-t-il lorsque vous livrez une nouvelle version de
L3
?L3
L2
travaux avecL3
, valider, ...L1
travaux avec de nouveauxL2
, ...P1
fonctionnement avec les nouvelles versions de toutes les bibliothèques:P1
l' intérieur de la copie de travail locale deL1
,L2
etL3
, récupérez les changements qui vous intéressent.git add L1 L2 L3
valider la nouvelle référence aux modulesP1
, tester, réviser, pull request, merge ...Méthodologie
Oui, cela nécessite des examens indépendants, car vous changez:
Seriez-vous mis hors service parce que vous livrez de la merde? (Peut-être pas, en fait). Si oui, vous devez effectuer des tests et revoir les modifications.
Avec les outils git appropriés (même
gitk
), vous pouvez facilement voir quelles versions des bibliothèques chaque projet utilise et vous pouvez les mettre à jour indépendamment en fonction de vos besoins. Les sous-modules sont parfaits pour votre situation et ne ralentiront pas votre processus.Vous pouvez peut-être trouver un moyen d' automatiser une partie de ce processus, mais la plupart des étapes ci-dessus nécessitent des cerveaux humains. Le moyen le plus efficace de gagner du temps serait de vous assurer que vos bibliothèques et vos projets sont faciles à faire évoluer. Si votre base de code peut gérer les nouvelles exigences avec élégance, les révisions de code seront plus simples et prendront peu de temps.
(Modifier) une autre chose qui pourrait vous aider est de regrouper les revues de code associées. Vous validez toutes les modifications et attendez de les propager vers toutes les bibliothèques et tous les projets qui les utilisent avant de sumbitting les demandes de tirage (ou avant de les prendre en charge). Vous finissez par faire un examen plus approfondi de toute la chaîne de dépendance. Cela peut peut-être vous aider à gagner du temps si chaque changement local est faible.
la source
Donc, ce que je comprends, c'est que pour P1, vous voulez changer l'interface L3 mais vous voulez que les autres P2 et P3 qui dépendent de l'interface L3 changent tout de suite. Il s'agit d'un cas typique de compatibilité descendante. Il y a un bel article sur cette préservation de la compatibilité descendante
Il existe plusieurs façons de résoudre ce problème:
OU
la source
Si je comprends bien votre problème:
Donc, l'objectif est que vous puissiez faire P1 et L1 en une fois, puis un mois plus tard, faire L2 et L3 dans un autre.
Dans le monde Java, c'est trivial, et peut-être la façon de travailler par défaut:
Vous pouvez donc avoir le code sur votre disque local pour L3 qui ne se compilerait pas s'il était en cours de compilation avec la copie du P1 dans l'autre répertoire de votre disque; heureusement, ce n'est pas le cas. Java peut le faire directement parce que les contes de compilation / liaison sont placés contre les fichiers jar compilés, pas le code source.
Je ne connais pas de solution préexistante largement utilisée à ce problème pour le monde C / C ++, et j'imagine que vous ne voulez guère changer de langue. Mais quelque chose pourrait facilement être piraté avec des fichiers de création qui ont fait la même chose:
Vous pourriez même utiliser le support C / C ++ dans maven , bien que la plupart des développeurs C vous regarderaient étrangement si vous le faisiez ...
la source
:)
Il existe une solution simple: couper les branches des versions sur l'ensemble du référentiel, fusionner tous les correctifs à toutes les versions activement expédiées (c'est facile en clair, cela devrait être possible dans git).
Toutes les alternatives créeront un horrible gâchis au fil du temps et avec la croissance du projet.
la source