144 votes

Fusion : Hg/Git vs SVN

J'ai souvent lu que Hg (et Git...) sont de mieux en mieux la fusion de SVN, mais je n'ai jamais vu des exemples pratiques de l'endroit où Hg/Git pouvez fusionner quelque chose où SVN échoue (ou SVN besoins intervention manuelle). Pourriez-vous envoyer un peu de l'étape-par-étape des listes de branche/modifier/commettre/...-les opérations qui montrent où SVN serait un échec alors que Hg/Git heureusement se déplace sur? Pratique, pas très des cas exceptionnels, s'il vous plaît...

Un peu de contexte: nous avons quelques dizaines de développeurs qui travaillent sur des projets d'utilisation de SVN, chaque projet (ou d'un groupe de projets similaires) dans son propre référentiel. Nous savons comment l'appliquer à libération et à la fonctionnalité des branches, afin de ne pas courir dans des problèmes très souvent (c'est à dire, nous avons été là, mais nous avons appris à surmonter Joël problèmes de "un programmeur causant un traumatisme pour l'ensemble de l'équipe" ou "besoin de six développeurs pour deux semaines à réintégrer une branche"). Nous avons de presse-branches, qui sont très stables et seulement utilisé pour appliquer des corrections de bugs. Nous avons des troncs d'arbres qui doivent être suffisamment stables pour être en mesure de créer une libération dans un délai d'une semaine. Et nous avons fonctionnalité-branches que seul les développeurs ou les groupes de développeurs peuvent travailler sur. Oui, ils sont supprimés après la réintégration, afin de ne pas encombrer le référentiel. ;)

Donc, je suis encore à essayer de trouver les avantages de Hg/Git sur le SVN. J'aimerais obtenir une certaine expérience pratique, mais il ne sont pas tous les grands projets que nous pourrions passer à Hg/Git encore, donc je suis bloqué, en jouant avec de petits artificielle des projets qui ne contiennent que quelques-uns des fichiers. Et je suis à la recherche de quelques cas où vous pouvez sentir la puissance impressionnante de Hg/Git, depuis ce jour, j'ai souvent lu sur eux, mais a échoué à trouver moi-même.

120voto

Martin Geisler Points 44779

Moi aussi, j'ai été à la recherche d'un cas où, disons, la Subversion ne parvient pas à fusionner une branche et de Mercurial (et Git, Bazaar, ...) fait la bonne chose.

Le SVN Livre décrit comment les fichiers renommés sont fusionnées de manière incorrecte. Cela s'applique à la Subversion 1.5, 1.6, 1.7et 1.8! J'ai essayé de recréer la situation ci-dessous:

cd /tmp
rm-rf svn-repo svn checkout
svnadmin create svn-repo
svn checkout file:///tmp/svn-repo svn checkout
cd svn checkout
mkdir tronc branches
echo 'Adieu, Monde!" > trunk/hello.txt
svn add tronc branches
svn commit -m 'importation Initiale.'
svn copy '^/trunk " '^/branches/renommer' -m 'Créer de la branche."
svn switch '^/trunk".
echo 'Hello, World!' > hello.txt
svn commit -m 'mise à Jour sur le tronc.'
svn switch '^/branches/rename".
svn renommer hello.txt hello.en.txt
svn commit -m 'Renommer sur la branche."
svn switch '^/trunk".
svn merge --réintégrer '^/branches/renommer'

Selon le livre, la fusion devrait se terminer proprement, mais avec de fausses données dans le fichier renommé depuis la mise à jour sur trunk est oublié. Au lieu de cela, je reçois un arbre de conflit (c'est avec Subversion 1.6.17, la nouvelle version de Debian au moment de la rédaction):

--- La fusion des différences entre le référentiel Url dans '.':
Un hello.en.txt
 C hello.txt
Résumé de conflits:
 Arbre de conflits: 1

Il ne devrait pas y avoir de conflit - la mise à jour devraient être intégrés dans le nouveau nom du fichier. Alors que la Subversion échoue, Mercurial gère correctement:

rm -rf /tmp/hg-repo
hg init /tmp/hg-repo
cd /tmp/hg-repo
echo 'Goodbye, World!' > hello.txt
hg add hello.txt
hg commit -m 'Initial import.'
echo 'Hello, World!' > hello.txt
hg commit -m 'Update.'
hg update 0
hg rename hello.txt hello.en.txt
hg commit -m 'Rename.'
hg merge

Avant la fusion, le dépôt ressemble à ceci (à partir de hg glog):

@ révision: 2:6502899164cc
| tag: conseil
| parent: 0:d08bcebadd9e
| user: Martin Geisler 
| date: Jeu Avr 01 12:29:19 2010 +0200
| résumé: Renommer.
|
| o de l'ensemble de modifications: 1:9d06fa155634
|/ l'utilisateur: Martin Geisler 
| date: Jeu Avr 01 12:29:18 2010 +0200
| résumé: la mise à Jour.
|
o révision: 0:d08bcebadd9e
 utilisateur: Martin Geisler 
 date: Jeu Avr 01 12:29:18 2010 +0200
 résumé: importation Initiale.

La sortie de la fusion:

la fusion hello.en.txt et hello.txt pour hello.en.txt
Fichiers 0 mis à jour, 1 fichiers fusionnés, 0 fichiers supprimés, les fichiers 0 non résolue
(direction de fusion, n'oubliez pas de valider)

En d'autres termes: Mercurial a eu le changement de la révision 1 et fusionné avec ce nouveau nom de fichier à partir de la révision 2 (hello.en.txt). La manipulation de ce cas est bien sûr essentiel pour le soutien de refactoring et de refactoring est exactement le genre de chose que vous voulez faire sur une branche.

91voto

Jakub Narębski Points 87537

Je ne suis pas d'utiliser Subversion moi-même, mais à partir des notes de publication pour la Subversion 1.5: suivi de Fusion (fondamentale) qu'il semble y avoir des différences suivantes à partir de combien de suivi de fusion un travail en full-DAG systèmes de contrôle de version comme Git ou Mercurial.

  • La fusion de tronc à la branche est différente de la fusion de la branche du tronc: pour une raison quelconque fusion tronc de la direction générale exige --reintegrate option d' svn merge.

    Dans la répartition de systèmes de contrôle de version comme Git ou Mercurial il n'y a pas de technique différence entre le tronc et les branches: toutes les branches sont créés égaux (il pourrait être social différence, tout de même). La fusion dans les deux sens est fait de la même façon.

  • Vous avez besoin de fournir de nouveaux -g (--use-merge-history) option d' svn log et svn blame de prendre le suivi de fusion en compte.

    Dans Git et Mercurial suivi de fusion est automatiquement pris en compte lors de l'affichage de l'historique (log) et de blâme. Dans Git, vous pouvez demander à suivre premier parent seul avec --first-parent (je suppose option similaire existe aussi pour Mercurial) à "jeter" fusionner les informations de suivi en git log.

  • Ce que je comprends svn:mergeinfo de la propriété de magasins par-chemin d'accès de l'information au sujet des conflits (la Subversion de l'ensemble de modifications), tandis que dans Git et Mercurial, il est tout simplement commettre des objets qui peuvent avoir plus d'un parent.

  • "Problèmes connus" paragraphe pour le suivi de fusion dans la Subversion suggère que l'exposition répétée / cyclique / réfléchissant de fusion peut ne pas fonctionner correctement. Cela signifie qu'avec la suite des histoires de deuxième fusion ne pourrait pas faire la bonne chose ('A' peut être tronc ou de la branche, et " B " peuvent être de la branche ou le tronc, respectivement):

 *---*---x---*---y---*---*---*---M2 <-- 
 \ \ /
 --*----M1---*---*---/ <-- B
 

Dans le cas ci-dessus ASCII-art est cassé: la division " B "est créé (fourche) à partir de la succursale" A "à la révision de "x", puis, plus tard, succursale " A "est fusionné à la révision de" y "dans la branche" B "fusion et publipostage "M1", et, enfin, succursale " B "est fusionné dans la branche" Une "fusion et publipostage "M2".

 *---*---x---*-----M1--*---*---M2 <-- 
 \ / / 
 \-*---y---*---*---/ <-- B
 

Dans le cas ci-dessus ASCII-art est cassé: la division " B "est créé (fourche) à partir de la succursale" A "à la révision de "x", il est fusionné en direction de 'A' à 'y' comme 'M1', et plus tard fusionné à nouveau en direction de " A "comme " M2".

*---b-----B1--M1--*---M3
 \ \ / /
 \ X /
 \ / \ /
\--B2--M2--*
 

Git gère cette situation très bien dans la pratique à l'aide de "récursive" fusion de la stratégie. Je ne suis pas sûr de Mercurial.

  • Dans "Problèmes Connus" , il s'agit d'un avertissement que le suivi de fusion mlgh pas le travail avec le fichier renomme, par exemple, quand d'un côté renomme le fichier (et peut-être la modifier), et le deuxième côté modifie le fichier sans le renommer (en vertu de l'ancien nom).

    Les deux Git et Mercurial gérer de tels cas, l'amende juste dans la pratique: Git à l'aide de renommer la détection, Mercurial aide de renommer le suivi.

HTH

17voto

VonC Points 414372

Sans parler des avantages habituels (hors ligne s'engage, processus de publication,...), voici une "fusion" exemple que j'aime bien:

Le scénario principal je continue à voir est une branche sur laquelle ... deux tâches distinctes sont réellement développés
(il a commencé à partir d'une fonction, mais il conduire à l'élaboration de cette autre entité.
Ou il a commencé à partir d'un patch, mais il conduire à l'élaboration d'une autre fonction).

Comment vous ne fusionner que l'un des deux sur la branche principale?
Ou Comment isoler les deux caractéristiques dans leurs propres branches?

Vous pouvez essayer de créer une sorte de patchs, le problème avec cela est que vous n'êtes pas sûr des dépendances fonctionnelles qui pourraient avoir existé entre:

  • les commits (ou révision SVN) utilisé dans vos patchs
  • l'autre s'engage à ne pas partie du patch

Git (et Mercurial trop je suppose) proposer le rebase --sur option à rebase (réinitialisation de la racine de la branche) de la partie de la branche:

De Jefromi post

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (v2-only) - x - x - x (wss)

vous pouvez démêler cette situation où vous avez des correctifs pour la v2 ainsi qu'une nouvelle wss fonction de:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - x - x (v2-only)
           \
             x - x - x (wss)

, vous permettant de:

  • test de chaque branche dans l'isolement pour vérifier si tout compiler et fonctionner comme prévu
  • fusionner uniquement ce que vous souhaitez principal.

L'autre caractéristique que j'aime (qui influence fusionne) est la capacité de squash s'engage (dans une branche pas encore poussé à l'autre pensions) dans le but de présenter:

  • un nettoyeur de l'histoire
  • s'engage qui sont plus cohérente (au lieu de commit1 pour fonction1, commit2 pour fonction2, commit3 de nouveau pour fonction1...)

Assurer des fusions, qui sont beaucoup plus facile, avec moins de conflits.

5voto

Paul S Points 4917

D'autres ont couvert les aspects plus théoriques de cette. Peut-être que je peux apporter un plus point de vue pratique.

Je suis actuellement en train de travailler pour une entreprise qui utilise SVN dans une "branche" du modèle de développement. C'est:

  • Aucun travail ne peut être fait sur le tronc
  • Chaque développeur peut avoir créer leurs propres branches
  • Les Branches dernier pour la durée de la tâche entreprise
  • Chaque tâche doit disposer de son propre branche
  • Fusionne avec le tronc doivent être autorisés (normalement via bugzilla)
  • De temps en temps quand un haut niveau de contrôle sont nécessaires, la fusion peut être réalisée par un gatekeeper

En général, il fonctionne. SVN peut être utilisé pour un flux comme ça, mais il n'est pas parfait. Il y a certains aspects de SVN qui obtenir de la manière et la forme du comportement humain. Ce qui lui donne certains aspects négatifs.

  • Nous avons eu quelques problèmes avec les gens de ramification à partir de points inférieur ^/trunk. Ce portées fusionner les informations des enregistrements de l'ensemble de l'arbre, et il se brise finalement le suivi de fusion. De faux conflits commencent à apparaître, et la confusion règne.
  • La cueillette des modifications à partir de tronc dans une branche est relativement simple. svn merge fait ce que vous voulez. Fusionner vos modifications (dit-on) --reintegrate sur la commande de fusion. Je n'ai jamais vraiment compris ce commutateur, mais cela signifie que la direction générale ne peut pas être fusionné dans le tronc de nouveau. Cela signifie que c'est une branche morte et vous devez en créer un nouveau pour continuer le travail. (Voir la note)
  • L'ensemble de l'entreprise de faire des opérations sur le serveur via des Url, lors de la création et de la suppression des branches vraiment confond et fait peur aux gens. Donc ils l'éviter.
  • La commutation entre les branches est facile de se tromper, laissant une partie de l'arbre à la recherche à la direction générale de la, tout en laissant l'autre partie à la recherche à la direction de B. Donc, les gens préfèrent faire leur travail dans une branche.

Ce qui tend à arriver, c'est qu'un ingénieur crée une succursale de la journée 1. Il commence son travail et les oublie. Quelques temps plus tard, un patron arrive et demande s'il peut libérer de son travail pour le tronc. L'ingénieur a été redoutant ce jour, car la réintégration signifie:

  • La fusion de sa longue durée de vie branche vers le tronc et la résolution de tous les conflits, et la libération de code non lié qui devraient avoir été dans une branche distincte, mais ne l'était pas.
  • La suppression de sa branche
  • Création d'une nouvelle branche
  • La commutation de sa copie de travail de la nouvelle branche

...et parce que l'ingénieur n'a cette aussi peu qu'ils le peuvent, ils ne peuvent pas se rappeler le "incantation magique" à chaque étape. Mal commutateurs et les Url de se produire, et tout à coup ils sont dans un désordre et ils vont chercher les "experts".

Finalement, tout s'installe, et les gens apprennent à faire avec les défauts, mais à chaque nouveau départ passe par les mêmes problèmes. L'éventuelle réalité (contrairement à ce que j'ai énoncé au début) est:

  • Aucun travail n'est fait sur le tronc
  • Chaque développeur a une branche importante
  • Les Branches dernier jusqu'à ce que le travail doit être libéré
  • Billet corrections de bugs ont tendance à obtenir leur propre branche
  • Fusionne avec le tronc se fait quand autorisés

...mais...

  • Parfois, au travail, à tronc quand il ne devrait pas car il est dans la même branche que quelque chose d'autre.
  • Les gens à éviter toute fusion (même les choses simples), de sorte que les gens travaillent souvent dans leur bulle
  • Big fusionne ont tendance à se produire et causer une quantité limitée de chaos.

Heureusement, l'équipe est assez petit pour s'en sortir, mais il ne serait pas à l'échelle. La chose est, aucun d'eux n'est un problème avec CVC, mais plus que parce que les fusions ne sont pas aussi importants que dans les DVCS ils ne sont pas aussi lisse. Que "la fusion de friction" les causes des comportements qui signifie qu'une "Branche" modèle commence à s'effriter. Bon fusionne besoin d'être une caractéristique de tous les VCS, et pas seulement DVCS.


Selon ce que maintenant il y a --record-only interrupteur qui pourrait être utilisée pour résoudre l' --reintegrate problème, et apparemment v1.8 choisit quand à faire un réintégrer automatiquement, et il ne cause pas de la branche à mort par la suite

3voto

Avant de subversion 1.5 (si je ne me trompe pas), subversion a eu un important dissadvantage en ce qu'elle ne se souviendrait pas de fusion de l'histoire.

Regardons le cas exposé par VonC:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - A - x (v2-only)
           \
             x - B - x (wss)

Avis des révisions A et B. vous Dire fusionné les changements de révision sur la "wss" branche de la "v2" de la branche à la révision B (pour quelque raison que ce soit), mais a continué à l'aide de deux branches. Si vous avez essayé de fusionner les deux branches, en utilisant à nouveau mercurial, ce ne serait que la fusion des modifications après les révisions et B. Avec subversion, vous auriez à la fusion de tout, comme si vous ne l'avez pas une fusion avant.

C'est un exemple tiré de ma propre expérience, où la fusion de B à A pris plusieurs heures en raison du volume de code: cela aurait été une vraie douleur pour traverser de nouveau, ce qui aurait été le cas avec la subversion de pré-1.5.

De l'autre, il est probablement plus pertinent de différence dans le comportement de fusion de Hginit: Subversion de rééducation:

Imaginez que vous et moi travaillons sur un peu de code, et nous branche de code, et chacun d'entre nous d'aller à la séparation de nos les espaces de travail et de faire des tas et des tas de les modifications de ce code séparément, de sorte ils ont divergé tout à fait un peu.

Lorsque nous avons à la fusion, à la Subversion essaie de regarder les deux révisions-mon modifié le code, et votre modifiés code-et il essaie de deviner comment smash ensemble dans un grand impie mess. Il échoue souvent, la production de des pages et des pages de "conflits de fusion" qui ne sont pas vraiment des conflits, tout simplement des endroits où la Subversion a échoué à comprendre ce que nous avons fait.

En revanche, alors que nous étions en train d' séparément dans Mercurial Mercurial a occupé à garder une série de révisions. Et donc, quand nous voulons rassembler notre code ensemble, Mercurial a fait un beaucoup plus d'information: il sait ce que chacun de nous a changé et peut réappliquer ces changements, plutôt que de simplement en regardant le produit final et en essayant de deviner comment le mettre ensemble.

En bref, de Mercurial façon d'analyser les différences est (était?) supérieure à la subversion.

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