Existe-t-il une différence entre les fusions dans svn et git ou mercurial?

12

D'après ma compréhension, SVN est «facile à créer. Difficile de fusionner ». Pourquoi donc? Y a-t-il une différence dans leur fusion?


la source

Réponses:

21

Veuillez consulter ma réponse Stack Overflow pour une situation très concrète où Mercurial (et Git) fusionne sans problème et où Subversion vous présente un faux conflit. La situation est un simple refactoring effectué sur une branche où vous renommez certains fichiers.

En ce qui concerne la réponse des tdammers, il y a alors un certain nombre de malentendus:

  • Subversion, Mercurial et Git tous les instantanés du projet à l'échelle du référentiel. Les appeler versions , révisions ou ensembles de modifications ne fait aucune différence. Ce sont tous des instantanés logiquement atomiques d'un ensemble de fichiers.

  • La taille de vos validations ne fait aucune différence en matière de fusion. Les trois systèmes fusionnent avec l'algorithme de fusion à trois voies standard et les entrées de cet algorithme sont

    • la plus grande version d'ancêtre commun
    • version sur une branche
    • version sur une autre branche

    Il n'a pas d' importance comment les deux versions de la branche ont été créées. Vous pouvez avoir utilisé 1000 petites validations depuis la version ancêtre, ou vous pouvez avoir utilisé 1 validation. Tout ce qui compte, c'est la version finale des fichiers. (Oui, c'est surprenant! Oui, beaucoup de guides DVCS se trompent horriblement.)

Il soulève également quelques bons points sur les différences:

  • Subversion a une certaine « voodoo » où vous pouvez fusionner à partir /trunken, disons, /branches/foo. Mercurial et Git n'utilisent pas ce modèle - les branches sont plutôt modélisées directement dans l'historique. L'histoire devient donc un graphe acyclique dirigé au lieu d'être linéaire. C'est un modèle beaucoup plus simple que celui utilisé par Subversion et cela supprime un certain nombre de cas d'angle.

  • Vous pouvez facilement retarder une fusion ou même laisser quelqu'un d'autre s'en occuper. Si cela hg mergevous donne une tonne de conflits, vous pouvez demander à votre collègue hg pullde vous et ensuite il a exactement le même état. Il peut donc hg mergeet peut -être qu'il est mieux à même de résoudre les conflits que vous.

    C'est très difficile avec Subversion où vous devez mettre à jour avant de pouvoir valider. Vous ne pouvez pas simplement ignorer les modifications sur le serveur et continuer à vous engager sur votre propre branche anonyme. En général, Subversion vous oblige à jouer avec une copie de travail sale lorsque vous svn update. C'est un peu risqué car vous n'avez pas stocké vos modifications dans un endroit sûr. Git et Mercurial vous permettent de valider d'abord, puis de mettre à jour et de fusionner si nécessaire.

La vraie raison pour laquelle Git et Mercurial fusionnent mieux que Subversion est une question d'implémentation. Il existe des conflits de changement de nom que Subversion ne peut tout simplement pas gérer même si la réponse correcte est claire. Mercurial et Git les manipulent facilement. Mais il n'y a aucune raison pour que Subversion ne puisse pas gérer cela aussi - la centralisation n'est certainement pas la raison.

Martin Geisler
la source
4
très bonne réponse! Je voterais deux fois si je le pouvais. :) J'ajouterais également que le livre SVN auquel vous vous référez dans la réponse SO admet clairement que "la fonctionnalité de suivi des fusions de Subversion a une implémentation interne extrêmement complexe ..." - cela seul est une assez bonne indication que la fonctionnalité n'est pas fiable
gnat
2
... et même avec cette implémentation extrêmement complexe, il est impossible de comprendre correctement l'ancêtre commun dans des cas simples.
Jan Hudec
À propos des fusions retardées - ne comprenez pas - avec SVN, mon collègue peut mettre à jour vers / checkout trunk, puis fusionner de ma branche vers celui-ci.
Gill Bates
@GillBates: Je parle d'une situation où vous n'avez pas démarré de branche pour votre travail - lorsque vous travaillez trunkdans SVN. Avec un DVCS, vous pouvez vous engager sans partager, mais dans SVN, vous svn commitaffecterez directement ceux qui travaillent sur la même branche. Même si nous travaillons tous les deux sur une branche dans SVN, je ne peux pas engager mon travail sans avoir à fusionner immédiatement avec votre travail. Cela rend les commits quelque peu effrayants - ce qui est une propriété effrayante pour un système de contrôle de version! :-)
Martin Geisler
6

Le problème principal réside dans la façon dont ces systèmes représentent une structure de répertoires versionnée.

Le concept de base de Subversion autour duquel tourne tout le système est celui d'une version (ou, dans le jargon svn, "révision"): un instantané d'un fichier à un certain point. Tant que l'historique est parfaitement linéaire, tout va bien, mais si vous devez fusionner les modifications de deux lignes de développement indépendantes, svn doit comparer les versions actuelles des deux, puis faire une comparaison à trois entre la dernière version partagée et les deux versions de tête. Les lignes qui semblent modifiées dans l'une des têtes, mais pas dans l'autre, peuvent facilement être résolues; les lignes qui s'écartent exactement de la même manière dans les deux têtes sont plus dures, mais généralement réalisables; les lignes qui s'écartent de différentes manières sont ce qui fait dire à svn "Je ne peux pas comprendre ça, humain, s'il te plait résous ça pour moi."

En revanche, git et mercurial track changesets plutôt que des versions. Le référentiel entier est un arbre de changesets, chacun dépendant d'un parent, où un changeset parent peut avoir n'importe quel nombre d'enfants, et la racine de l'arbre représente un répertoire vide. En d'autres termes, git / hg dit "d'abord je n'avais rien, puis ce patch a été appliqué, puis ce patch, etc.". Lorsque vous devez fusionner deux lignes de développement, git / hg sait non seulement à quoi ressemble chaque tête actuellement, et à quoi ressemblait la dernière version commune, mais il sait également comment la transition s'est produite, permettant une fusion beaucoup plus intelligente.

Une autre chose qui facilite la fusion dans un DVCS est une conséquence indirecte de la séparation des concepts de commit et de push, et d'autoriser à tout moment toutes sortes de fusions croisées entre deux clones du même référentiel. Avec svn, les utilisateurs ont tendance à valider des ensembles de modifications volumineux avec des modifications souvent indépendantes, car une validation est également une mise à jour du référentiel central qui affecte tous les autres membres de l'équipe; si vous commettez une version cassée, tout le monde sera en colère contre vous. Étant donné que la plupart des configurations impliquent un serveur svn en réseau, la validation implique également le pompage de données sur le réseau, ce qui signifie que la validation introduit un retard considérable dans le flux de travail (en particulier lorsque votre copie de travail est obsolète et que vous devez d'abord tirer). Avec git et mercurial, la validation se produit localement, et parce que les deux sont très efficaces pour gérer les systèmes de fichiers locaux, elle se termine généralement instantanément. En conséquence, les gens (une fois qu'ils s'y sont habitués) commettent de petits changements incrémentiels, puis quand cela fonctionne, pousser une douzaine de commits en une seule fois. Ensuite, lorsque le temps de fusion arrive, le SCM dispose d'informations beaucoup plus détaillées et peut mieux résoudre les conflits en toute sécurité et automatiquement.

Et puis il y a les jolis détails qui rendent les choses encore plus faciles:

  • Vous pouvez avoir plusieurs têtes et toujours vous engager sur l'une ou l'autre; contrairement à la subversion, vous n'avez pas besoin de combiner l'extraction, la mise à jour et la fusion avant de recommencer - les têtes multiples restent telles quelles jusqu'à ce que vous choisissiez de fusionner
  • Les répertoires ne sont pas traités spécialement; au lieu de cela, le chemin n'est considéré que comme un grand nom de fichier et tous vos répertoires doivent être à la même révision à tout moment. Cela signifie que vous ne pouvez pas faire le vaudou de subversion où les sous-dossiers d'un projet sont à différentes révisions, mais cela signifie également que la copie de travail est moins susceptible de devenir un énorme gâchis cassé ingérable, et plus intéressant encore, un mouvement n'est pas représenté comme une suppression -et-ajouter (qui se briserait entièrement dans svn s'il n'y avait pas les métadonnées de modification), mais simplement comme un renommage; si vous déplacez un fichier, tout son historique est conservé; la fusion peut même appliquer des modifications au fichier déplacé qui ont été apportées à une version non déplacée du même fichier après le déplacement, dans une autre branche
  • La plupart du temps, vous n'avez même pas besoin de créer de branche: à la place, vous clonez simplement le référentiel entier. Le clonage est bon marché, surtout s'il est fait sur le même système de fichiers, et si vous décidez de vous débarrasser du clone, vous supprimez simplement le répertoire dans lequel il vit et c'est tout. Vous n'avez même pas besoin d'utiliser hg ou git pour cela.
  • Il y a peu (le cas échéant) de restrictions sur ce que vous pouvez fusionner. Vous pouvez avoir six clones du même référentiel et fusionner (ou plutôt, pousser ou tirer; une fusion explicite n'est souvent pas requise) de A vers B, puis C vers B, puis B vers D, puis C vers D, B retour à A, D à E, à tout moment et aussi souvent que vous le souhaitez.
  • Vous pouvez tester une fusion en clonant l'un des référentiels que vous souhaitez fusionner, puis en tirant dessus de l'autre. S'il fait ce que vous voulez, vous pouvez repousser vers la cible réelle, sinon, vous jetez le clone et recommencez.
tdammers
la source
2
Je dois mentionner quelques corrections et ajoute à la réponse: 1. Les révisions SVN sont globales par référentiel , la révision représente tous les fichiers en dépôt à un moment donné 2. La technologie de fusion est fondamentalement commune dans SVN et DVCS - si le fichier dans les fichiers de fusion n'a changé que le de la même manière , la fusion produira le même nombre de conflits pour SVN et DVCS - tous les SCM fonctionnent toujours au niveau de la chaîne, pas un bloc logique 3. Les gros commits dans SVN ne sont pas le résultat d'une faiblesse architecturale, mais parce que les utilisateurs sont souvent des idiots paresseux - ils ignorent les schémas de base. Branch | merge fonctionne dans SVN, si / dev / brain et / dev / hands fonctionnent
Lazy Badger
2
Partie 2: La fusion intelligente dans DVCS se produit principalement parce que, contrairement à Subversion, ils suivent et gèrent les mouvements de renommage des fichiers et SVN ne le fait pas du tout, donc - toute opération, qui traite le fichier, a changé d'un côté et renommé sur deuxièmement, échouera. Le branchement avec des branches et le clonage ne sont que des stratégies différentes de branchement avec les mêmes droits de vivre, dont l'utilisation "... dépend de ..."
Lazy Badger
@LazyBadger: Au contraire. Subversion suit les mouvements / renommages, ce qui provoque de faux conflits en partie parce que la gestion des renommages en fusion est simplement boguée et en partie parce qu'il y a des cas d'angle difficiles ou impossibles à gérer correctement. La dernière est pourquoi git (et mercurial l'a copié) par conception ne suit pas les renommages et les devine lors de la fusion. Ce qui fonctionne bien si le contenu est toujours assez similaire pour être fusionné (c'est à ce moment-là que vous en avez besoin) et ne fait pas de bêtises autrement.
Jan Hudec
@JanHudec - désolé, la poignée SVN ne se déplace pas | renomme à une seule action atomique (façon DVCS - "renommer"), mais comme "supprimer + ...", donc - produit des conflits d'arborescence, où cela ne se produit pas en DVCS ( vrai renommer ). Mercurial track renomme explicitement ( hg mvou hg addremove --similarity...), tandis que Git utilise l'heuristique, mais les deux gèrent les renommages . Je peux obtenir un conflit d'arbre même avec 1 différence de chaîne dans les fichiers fusionnés! Vous devez réapprendre certains aspects de Subversion, désolé.
Lazy Badger
5
Maintenant, nous devenons assez techniques :-) Les copies de pistes de Subversion et Mercurial , pas de renommage. Les deux systèmes effectuent le suivi au rename a bfur copy a b; remove aet à mesure que les deux le font dans un commit atomique. La différence de comportement de fusion provient de la gestion différente des cas d'angle et de Subversion permettant plus de fusions que Mercurial et Git. Enfin, Git détecte les renommages au moment de la fusion et de l'enregistrement - nous envisageons également d'ajouter cela dans Mercurial.
Martin Geisler