130 votes

Mercurial : Nommé Branches vs plusieurs référentiels

Nous sommes actuellement en utilisant subversion sur une relativement grande base de code. Chaque version a sa propre branche, et des corrections sont effectuées sur le tronc et a migré dans la libération des branches à l'aide de svnmerge.py

Je crois que le moment est venu de passer à une meilleure contrôle de code source, et j'ai joué avec Mercurial pour un certain temps.

Il semble y avoir deux écoles de pensée sur la gestion de cette libération de la structure à l'aide de Mercurial. Soit chaque version a sa propre repo, et des corrections sont apportées par rapport à la branche de version et poussé à la branche principale (et de toute autre version plus récente branches.) OU à l'aide de branches nommées au sein d'un référentiel unique (ou plusieurs correspondant copies.)

Dans les deux cas, il semble que je pourrais être en utilisant quelque chose comme la transplantation de cherrypick changements pour l'inclusion dans la libération des branches.

Je vous demande, quelles sont les mérites relatifs de chaque approche?

129voto

Martin Geisler Points 44779

La plus grande différence est la façon dont la direction de noms sont inscrits dans l'histoire. Avec les branches nommées le nom de la branche est incorporé dans chaque révision et deviendra ainsi une partie immuable de l'histoire. Avec les clones il n'y aura aucune trace de l'emplacement d'un ensemble de modifications sont venus.

Cela signifie que les clones sont grands pour rapide des expériences où vous ne voulez pas enregistrer un nom de branche, et les branches nommées sont bonnes pour le long terme branches ("1.x", "2.x" et similaires).

Notez également qu'un référentiel unique peut facilement accueillir plusieurs de la lumière-poids branches de Mercurial. Ces en–dépôt, les branches peuvent être mis en signet, de sorte que vous pouvez facilement les retrouver. Disons que vous avez cloné le référentiel d'entreprise quand il a regardé comme ça:

[a] --- [b]

Vous bidouiller et faire [x] et [y]:

[a] --- [b] --- [x] --- [y]

Dire alors que quelqu'un met des [c] et [d] dans le référentiel, de sorte que lorsque vous tirez, vous obtenez un graphique comme ceci:

 [x] --- [y]
/
[a] --- [b] --- [c] --- [d]

Ici il y a deux têtes dans un référentiel unique. Votre copie de travail reflètent toujours un seul ensemble de modifications, la soi-disant copie de travail du parent de l'ensemble de modifications. Vérifier avec:

% hg parents

Disons que c'rapports d' [y]. Vous pouvez voir les têtes avec des

% hg heads

et ceci en rapport [y] et [d]. Si vous voulez mettre à jour votre référentiel propre à la caisse d' [d], puis il suffit de faire (remplacer [d] avec le numéro de révision de [d]):

% hg update --clean [d]

Vous verrez alors qu' hg parents rapport [d]. Cela signifie que votre prochain commit aura [d] en tant que parent. Vous pouvez ainsi corriger un bug que vous avez remarqué dans la branche principale et de créer un changeset [e]:

 [x] --- [y]
/
[a] --- [b] --- [c] --- [d] --- [e]

Pour pousser changeset [e] seulement, ce que vous devez faire

% hg push -r [e]

[e] est la révision de hachage. Par défaut hg push sera tout simplement de comparer les référentiels et de voir qu' [x], [y], et [e] sont manquantes, mais vous pourriez ne pas vouloir partager [x] et [y] encore.

Si la correction des effets aussi vous, vous voulez fusionner avec votre branche:

% hg update [y]
% hg merge

Qui laissera votre référentiel graphique ressemblant à ceci:

 [x] --- [y] ----------- [z]
 / /
[a] --- [b] --- [c] --- [d] --- [e]

[z] est la fusion entre l' [y] et [e]. Vous pourriez aussi avoir opté pour lancer la direction générale de suite:

% hg strip [x]

Mon point principal de cette histoire est: un seul clone permet de représenter facilement plusieurs pistes de développement. Cela a toujours été vrai pour "plaine hg" sans l'aide de toutes les extensions. Les signets de l'extension est d'une grande aide, cependant. Il vous permettra d'attribuer des noms (signets) pour les révisions. Dans le cas ci-dessus, vous souhaitez créer un signet sur le développement de votre tête et l'autre sur l'amont de la tête. Les signets peuvent être poussés et tirés Mercurial 1.6 et sont devenus une caractéristique Mercurial 1.8.

Si vous aviez opté pour deux clones, le développement de votre clone aurait ressemblait à ça après avoir fait [x] et [y]:

[a] --- [b] --- [x] --- [y]

Et votre en amont clone contiendra:

[a] --- [b] --- [c] --- [d]

Vous remarquez maintenant le bug et le corriger. Ici, vous n'avez pas à hg update depuis l'amont clone est prêt à l'emploi. De vous engager et de créer [e]:

[a] --- [b] --- [c] --- [d] --- [e]

Pour inclure la correction dans le développement de votre clone vous tirer de là:

[a] --- [b] --- [x] --- [y]
\
 [c] --- [d] --- [e]

et de la fusion:

[a] --- [b] --- [x] --- [y] --- [z]
 \ /
 [c] --- [d] --- [e]

Le graphique peut semble différent, mais il a la même structure et le résultat final est le même. À l'aide de clones que vous avait à faire un peu moins de la comptabilité mentale.

Les branches nommées n'ont pas vraiment dans la photo ici parce qu'ils sont tout à fait facultatif. Mercurial a été mise au point à l'aide de deux clones pendant des années avant que nous nous sommes mis à l'aide de branches nommées. Nous maintenons une branche appelée "stable" en plus "par défaut" de la branche et de faire de nos communiqués de presse basée sur la "stable" de la branche. Voir la norme ramification de la page dans le wiki pour obtenir une description du flux de travail recommandé.

29voto

Norman Ramsey Points 115730

Je pense que vous voulez l'ensemble de l'histoire dans un repo. La ponte sur une courte durée repo est pour des expériences de courte durée, pas de grands événements comme les communiqués de presse.

L'une des déceptions de la Mercurial, c'est qu'il semble y avoir aucun moyen facile de créer une courte durée de vie de la branche, de jouer avec elle, de l'abandonner, et de collecter les ordures. Les Branches sont toujours. Je compatis à ne jamais vouloir abandonner l'histoire, mais le super-bon marché, jetables, les branches sont un git fonctionnalité que j'aimerais vraiment voir en hg.

14voto

Geoffrey Zheng Points 3503

Vous devriez faire les deux.

Démarrer avec l'acceptées réponse de @Norman: Utilisation d'un référentiel avec une branche nommée par libération.

Ensuite, avoir un clone par communiqué de la direction générale pour la construction et l'essai.

Une des clés est à noter que même si vous utilisez plusieurs dépôts, vous devriez éviter d'utiliser des transplant de déplacer les révisions entre eux parce que 1) il change de hachage, et 2) il peut introduire des bogues qui sont très difficiles à détecter quand il y a des modifications conflictuelles entre la révision de vous et de transplantation de la branche cible. Vous voulez faire l'habitude de fusion à la place (et sans premerge: vérifiez toujours l'état de la fusion), qui sera la conséquence de ce @mg a déclaré à la fin de sa réponse:

Le graphique peut semble différent, mais il a la même structure et le résultat final est le même.

De plus avec beaucoup de détails, si vous utilisez plusieurs dépôts, le "tronc" du référentiel (ou à défaut, du principal, développement, peu importe) contient TOUTES les révisions dans TOUS les référentiels. Chacune de presse/direction de référentiel est simplement une branche dans le coffre, le tout fusionné en arrière d'une manière ou d'une autre dans le tronc, jusqu'à ce que vous voulez laisser une ancienne version de retard. Par conséquent, la seule vraie différence entre le fait que les pensions et les pensions dans le nom de la branche schéma est simplement de savoir si les branches sont nommés ou non.

Qui devrait le rendre évident pourquoi j'ai dit "démarrer avec un repo". Que seul repo est le seul endroit où vous aurez besoin de regarder pour tout ensemble de modifications dans une version. Vous pouvez balise de révisions sur la libération des branches pour la gestion des versions. C'est conceptuellement simple et claire, et fait de l'administrateur système plus simple, car c'est la seule chose qui doit absolument être disponibles et récupérables à tout moment.

Mais vous avez encore besoin de maintenir un clone par branche/version que vous avez besoin pour construire et tester. Il est trivial comme vous pouvez vous en hg clone <main repo>#<branch> <branch repo>, puis hg pull dans la branche des pensions de tirer uniquement de nouvelles révisions à la branche (plus ancêtre des révisions sur les premières branches qui ont fusionné).

Cette configuration la mieux adaptée le noyau linux modèle de validation de l' unique extracteur (n'est-il pas se sentir bien à agir comme Seigneur de Linus. Au sein de notre société que nous appelons le rôle intégrateur), en tant que principal repo est la seule chose que les développeurs ont besoin de cloner et de l'extracteur doit tirer dans. L'entretien de la branche repos est purement pour la gestion de la publication et peuvent être entièrement automatisés. Les développeurs n'ont jamais besoin de retirer de pousser à la direction des pensions de titres.


Voici @mg l'exemple refondu pour cette installation. Point de départ:

[a] - [b]

Faire une branche nommée pour une version, disons "1.0", quand vous arrivez à la version alpha. Engager les corrections de bugs:

[a] - [b] ------------------ [m1]
         \                 /
          (1.0) - [x] - [y]

(1.0) n'est pas un vrai ensemble de modifications depuis nommé branche n'existe pas jusqu'à ce que vous vous engagez. (Vous pourriez faire un trivial s'engager, comme l'ajout d'un tag, assurez-vous que les branches nommées sont correctement créés.)

La fusion [m1] est la clé de cette installation. Contrairement à un développeur référentiel où il peut y avoir un nombre illimité de chefs, vous ne voulez PAS d'avoir plusieurs têtes dans votre repo (sauf pour les vieux, morts branche de version comme mentionné précédemment). Donc, chaque fois que vous avez de nouvelles révisions à la libération des branches, vous devez fusionner les de les ramener à la branche par défaut (ou d'une version ultérieure de la branche) immédiatement. Cela garantit que toute correction d'un bug dans une version est également inclus dans toutes les versions ultérieures.

Dans le même temps de développement sur la branche par défaut se poursuit vers la prochaine version:

          ------- [c] - [d]
         /
[a] - [b] ------------------ [m1]
         \                 /
          (1.0) - [x] - [y]

Et comme d'habitude, vous avez besoin de fusionner les deux têtes sur la branche par défaut:

          ------- [c] - [d] -------
         /                         \
[a] - [b] ------------------ [m1] - [m2]
         \                 /
          (1.0) - [x] - [y]

Et c'est la 1.0 branche clone:

[a] - [b] - (1.0) - [x] - [y]

Maintenant c'est un exercice d'ajouter la prochaine version de la branche. Si c'est 2.0, puis il va certainement branche par défaut. Si c'est 1.1, vous pouvez choisir de bifurquer 1.0 ou par défaut. Peu importe, toute nouvelle révision 1,0 doit d'abord être fusionné à la branche suivante, alors que par défaut. Ceci peut être fait automatiquement si il n'y a pas de conflit, résultant en un simple vide de fusion.


J'espère que l'exemple fait mes premiers points. En résumé, les avantages de cette approche est la suivante:

  1. Référence unique référentiel qui contient complète de l'ensemble de modifications et la version de l'histoire.
  2. Claire et simplifiée de la gestion des release.
  3. Claire et simplifiée de flux de travail pour les développeurs et intégrateurs.
  4. Faciliter le déroulement des opérations d'itérations (revues de code) et de l'automatisation (automatique vide de fusion).

Mise à JOUR hg lui-même ne se présente: le principal repo contient la valeur par défaut et stable branches, et l' stable repo est la branche stable clone. Il n'utilise pas de version de la branche, cependant, que la version des balises le long de la branche stable sont assez bon pour sa libération des fins de gestion.

5voto

dwc Points 12676

La différence majeure, pour autant que je sache, est quelque chose que vous avez déjà déclaré: les branches nommées sont regroupées dans un seul référentiel. Les branches nommées ont tout à portée de main. Les repos séparés sont plus petits et faciles à déplacer. La raison pour laquelle il existe deux écoles de pensée à ce sujet est qu’il n’ya pas de gagnant clair. Les arguments les plus judicieux pour vous sont probablement ceux avec lesquels vous devriez aller, car il est probable que leur environnement ressemble beaucoup au vôtre.

2voto

thSoft Points 5513

Je pense que c'est clairement une décision pragmatique en fonction de la situation actuelle, par exemple la taille d'une fonctionnalité / refonte. Je pense que les forks sont vraiment bien pour les contributeurs avec des rôles qui ne sont pas encore au point de rejoindre l'équipe de développeurs en prouvant leur aptitude à gérer des frais techniques négligeables.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X