La plus grande différence réside dans la manière dont les noms des branches sont enregistrés dans l'historique. Avec les branches nommées, le nom de la branche est intégré dans chaque changeset et deviendra ainsi une partie immuable de l'historique. Avec les clones, il n'y aura pas d' enregistrement permanent de l'origine d'un ensemble de modifications particulier.
Cela signifie que les clones sont parfaits pour les expériences rapides où vous ne voulez pas enregistrer un nom de branche, et les branches nommées sont bonnes pour les branches à long terme ("1.x", "2.x" et similaires).
Notez également qu'un seul référentiel peut facilement accueillir plusieurs branches légères dans Mercurial. De telles branches dans le référentiel peuvent être mises en signet afin que vous puissiez facilement les retrouver. Disons que vous avez cloné le référentiel de l'entreprise quand il ressemblait à ceci:
[a] --- [b]
Vous piratez et faites [x]
et [y]
:
[a] --- [b] --- [x] --- [y]
Cela signifie que quelqu'un met [c]
et [d]
dans le référentiel, donc lorsque vous tirez, vous obtenez un graphique d'historique comme celui-ci:
[x] --- [y]
/
[a B c d]
Ici, il y a deux têtes dans un seul référentiel. Votre copie de travail reflétera toujours un seul changeset, le jeu de modifications parent de la copie de travail. Vérifiez ceci avec:
% hg parents
Disons qu'il rapporte [y]
. Vous pouvez voir les têtes avec
% hg heads
et cela rapportera [y]
et [d]
. Si vous souhaitez mettre à jour votre référentiel pour une extraction propre de [d]
, alors faites simplement (remplacez-le [d]
par le numéro de révision pour [d]
):
% hg update --clean [d]
Vous verrez alors ce hg parents
rapport [d]
. Cela signifie que votre prochain commit aura [d]
pour parent. Vous pouvez ainsi corriger un bug que vous avez remarqué dans la branche principale et créer un changeset [e]
:
[x] --- [y]
/
[a] --- [b] --- [c] --- [d] --- [e]
Pour pousser le changeset [e]
uniquement, vous devez faire
% hg push -r [e]
où [e]
est le hachage du changeset. Par défaut hg push
, vous comparerez simplement les référentiels et verrez que [x]
, [y]
et [e]
sont manquants, mais vous ne voudrez peut-être pas partager [x]
et [y]
encore.
Si le correctif vous affecte également, vous souhaitez le fusionner avec votre branche de fonctionnalités:
% hg update [y]
% hg merge
Cela laissera votre graphique de référentiel ressemblant à ceci:
[x] --- [y] ----------- [z]
/ /
[a] --- [b] --- [c] --- [d] --- [e]
où [z]
est la fusion entre [y]
et [e]
. Vous pourriez également avoir choisi de jeter la branche:
% hg strip [x]
Mon point principal de cette histoire est le suivant: un seul clone peut facilement représenter plusieurs pistes de développement. Cela a toujours été vrai pour "plain hg" sans utiliser d'extensions. L' extension de signets est cependant d'une grande aide. Il vous permettra d'attribuer des noms (signets) aux changesets. Dans le cas ci-dessus, vous voudrez un signet sur votre tête de développement et un sur la tête en amont. Les signets peuvent être poussés et extraits avec Mercurial 1.6 et sont devenus une fonctionnalité intégrée à Mercurial 1.8.
Si vous aviez choisi de créer deux clones, votre clone de développement aurait ressemblé à ceci après avoir créé [x]
et [y]
:
[a] --- [b] --- [x] --- [y]
Et votre clone en amont contiendra:
[a] --- [b] --- [c] --- [d]
Vous remarquez maintenant le bogue et corrigez-le. Ici, vous n'avez pas à le faire hg update
car le clone en amont est prêt à être utilisé. Vous vous engagez et créez [e]
:
[a] --- [b] --- [c] --- [d] --- [e]
Pour inclure le correctif dans votre clone de développement, insérez-le ici:
[a] --- [b] --- [x] --- [y]
\
[c] --- [d] --- [e]
et fusionner:
[a] --- [b] --- [x] --- [y] --- [z]
\ /
[c] --- [d] --- [e]
Le graphique peut sembler différent, mais il a la même structure et le résultat final est le même. En utilisant les clones, vous deviez faire une comptabilité un peu moins mentale.
Les branches nommées ne sont pas vraiment entrées dans l'image ici car elles sont assez optionnelles. Mercurial lui-même a été développé en utilisant deux clones pendant des années avant de passer à l'utilisation de branches nommées. Nous maintenons une branche appelée 'stable' en plus de la branche 'default' et créons nos versions basées sur la branche 'stable'. Voir la page de branchement standard dans le wiki pour une description du flux de travail recommandé.
Je pense que vous voulez l'intégralité de l'historique en un seul dépôt. La création d'un repo à court terme est destinée à des expériences à court terme, pas à des événements majeurs tels que les versions.
L'une des déceptions de Mercurial est qu'il ne semble pas y avoir de moyen facile de créer une branche éphémère, de jouer avec, de l'abandonner et de ramasser les ordures. Les branches sont éternelles. Je sympathise avec le fait de ne jamais vouloir abandonner l'histoire, mais les branches jetables très bon marché sont une
git
fonctionnalité que j'aimerais vraiment voirhg
.la source
hg strip
c'est ce que je veux. Pourquoi la documentation en ligne prétend-elle que les branches ne peuvent pas être supprimées?hg ci --close-branch
.Vous devriez faire les deux .
Commencez par la réponse acceptée de @Norman: utilisez un référentiel avec une branche nommée par version.
Ensuite, ayez un clone par branche de version pour la construction et les tests.
Une note clé est que même si vous utilisez plusieurs référentiels, vous devez éviter d'utiliser
transplant
pour déplacer des ensembles de modifications entre eux car 1) cela change le hachage et 2) cela peut introduire des bogues très difficiles à détecter lorsqu'il y a des changements conflictuels entre l'ensemble de modifications que vous greffe et la branche cible. Vous voulez faire la fusion habituelle à la place (et sans prémerge: inspectez toujours visuellement la fusion), ce qui entraînera ce que @mg a dit à la fin de sa réponse:Plus en détail, si vous utilisez plusieurs référentiels, le référentiel "trunk" (ou par défaut, main, développement, peu importe) contient TOUS les changesets dans TOUS les référentiels. Chaque référentiel de version / branche est simplement une branche dans le tronc, tous fusionnés dans un sens ou dans l'autre vers le tronc, jusqu'à ce que vous vouliez laisser une ancienne version derrière. Par conséquent, la seule vraie différence entre ce repo principal et le repo unique dans le schéma de succursales nommées est simplement de savoir si les succursales sont nommées ou non.
Cela devrait rendre évident la raison pour laquelle j'ai dit "commencer par un dépôt". Ce dépôt unique est le seul endroit où vous aurez besoin de rechercher un ensemble de modifications dans n'importe quelle version . Vous pouvez baliser d'autres ensembles de modifications sur les branches de version pour la gestion des versions. C'est conceptuellement clair et simple, et simplifie l'administration système, car c'est la seule chose qui doit absolument être disponible et récupérable à tout moment.
Mais alors, vous devez toujours maintenir un clone par branche / version que vous devez construire et tester. C'est trivial comme vous pouvez
hg clone <main repo>#<branch> <branch repo>
, puishg pull
dans le repo de branche, vous ne tirerez que de nouveaux ensembles de modifications sur cette branche (plus les ensembles de modifications ancêtres sur les branches précédentes qui ont été fusionnées).Cette configuration correspond le mieux au modèle de commit du noyau Linux de l' extracteur unique (n'est-il pas bon d'agir comme Lord Linus. Dans notre entreprise, nous appelons l' intégrateur de rôle ), car le dépôt principal est la seule chose que les développeurs doivent cloner et le l'extracteur doit entrer. La maintenance des dépôts de succursale est purement pour la gestion des versions et peut être complètement automatisée. Les développeurs n'ont jamais besoin de tirer / pousser vers les dépôts de branche.
Voici l'exemple de @ mg refondu pour cette configuration. Point de départ:
Créez une branche nommée pour une version finale, dites "1.0", lorsque vous arrivez à la version alpha. Commit des corrections de bogues dessus:
(1.0)
n'est pas un vrai changeset car la branche nommée n'existe pas tant que vous ne vous engagez pas. (Vous pouvez faire un commit trivial, comme ajouter une balise, pour vous assurer que les branches nommées sont correctement créées.)La fusion
[m1]
est la clé de cette configuration. Contrairement à un référentiel de développeurs où il peut y avoir un nombre illimité de têtes, vous ne voulez PAS avoir plusieurs têtes dans votre référentiel principal (sauf pour l'ancienne branche de version morte comme mentionné précédemment). Ainsi, chaque fois que vous avez de nouveaux ensembles de modifications sur des branches de version, vous devez les fusionner immédiatement avec la branche par défaut (ou une branche de version ultérieure). Cela garantit que tout correctif de bogue dans une version est également inclus dans toutes les versions ultérieures.En attendant, le développement sur la branche par défaut se poursuit vers la prochaine version:
Et comme d'habitude, vous devez fusionner les deux têtes sur la branche par défaut:
Et voici le clone de branche 1.0:
C'est maintenant un exercice pour ajouter la branche de version suivante. Si c'est 2.0, alors il se ramifiera certainement par défaut. Si c'est 1.1, vous pouvez choisir de bifurquer 1.0 ou par défaut. Quoi qu'il en soit, tout nouvel ensemble de modifications sur 1.0 doit d'abord être fusionné avec la branche suivante, puis par défaut. Cela peut être fait automatiquement s'il n'y a pas de conflit, résultant simplement en une fusion vide.
J'espère que l'exemple clarifie mes points précédents. En résumé, les avantages de cette approche sont:
UPDATE hg lui - même le fait : le référentiel principal contient les branches par défaut et stables, et le référentiel stable est le clone de branche stable. Cependant, il n'utilise pas de branche versionnée, car les balises de version le long de la branche stable sont suffisantes pour ses besoins de gestion des versions.
la source
La différence majeure, pour autant que je sache, est quelque chose que vous avez déjà déclaré: les nommés branchés sont dans un seul référentiel. Les branches nommées ont tout à portée de main en un seul endroit. Les dépôts séparés sont plus petits et faciles à déplacer. La raison pour laquelle il y a deux écoles de pensée à ce sujet est qu'il n'y a pas de gagnant clair. Quel que soit l'argumentation de votre camp qui a le plus de sens pour vous, c'est probablement celle avec laquelle vous devriez aller, car il est probable que leur environnement soit le plus similaire au vôtre.
la source
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 bons pour les contributeurs qui n'ont pas encore de rôle de commettant pour rejoindre l'équipe de développeurs en prouvant leur aptitude avec une surcharge technique négligeable.
la source
Je déconseille vraiment d'utiliser des branches nommées pour les versions. C'est vraiment à cela que servent les balises. Les branches nommées sont destinées à des détournements de longue durée, comme une
stable
branche.Alors pourquoi ne pas simplement utiliser des balises? Un exemple basique:
Cela créera une nouvelle tête sans nom sur la
default
branche, aka. une branche anonyme, ce qui est parfaitement bien en hg. Vous pouvez alors à tout moment fusionner les commits de correction de bogue dans la piste de développement principale. Pas besoin de branches nommées.la source