409 votes

Comment et/ou pourquoi la fusion est dans Git mieux que dans le SVN?

J'ai entendu quelques-uns des endroits que l'un des principaux moyens de contrôle de version distribué des systèmes de cireur, est beaucoup mieux de fusionner qu'avec les outils traditionnels comme SVN. Est-ce en fait dus à des différences inhérentes entre les deux systèmes de travail, ou faire spécifique DVCS implémentations comme Git/Mercurial suffit plus malin fusion des algorithmes de SVN?

567voto

Spoike Points 32082

La demande de pourquoi la fusion est mieux dans un DVCS que dans la Subversion a été en grande partie basée sur la façon dont la ramification et la fusion travaillé dans Subversion, il y a un moment. Subversion avant 1.5.0 ne pas stocker toutes les informations au sujet de quand les branches ont été fusionnés, ainsi, lorsque vous avez voulu fusionner vous deviez spécifier la plage de révisions qui ont été fusionnés.

Alors, pourquoi ne Subversion fusionne sucer?

Méditer sur cet exemple:

      1   2   4     6     8
trunk o-->o-->o---->o---->o
       \
        \   3     5     7
b1       +->o---->o---->o

Lorsque l'on veut fusionner b1 changements dans le coffre, nous avions la commande suivante, en se tenant debout sur un dossier qui a le tronc extrait:

svn merge -r 3:7 {link to branch b1}

... qui vont tenter de fusionner les changements d' b1 dans votre répertoire local de travail. Et puis vous validez les modifications une fois que vous résoudre les conflits et testé le résultat. Lorsque vous validez la révision de l'arbre devrait ressembler à ceci:

      1   2   4     6     8   9
trunk o-->o-->o---->o---->o-->o      "the merge commit is at r9"
       \
        \   3     5     7
b1       +->o---->o---->o

Cependant, cette manière de spécifier des plages de révisions obtient rapidement de la main lorsque la version arbre pousse comme de la subversion n'ai pas de méta-données sur quand et quelles modifications ai fusionné ensemble. Réfléchir sur ce qui se passe plus tard:

           12        14
trunk  …-->o-------->o
                                     "Okay, so when did we merge last time?"
              13        15
b1     …----->o-------->o

C'est en grande partie une question par le référentiel de la conception que de la Subversion a, afin de créer une direction générale, vous devez créer un nouveau répertoire virtuel dans le référentiel qui permettra de la maison une copie du tronc, mais il n'a pas de stocker toutes les informations au sujet de quand et ce que les choses se sont fusionnées. Qui va conduire à de mauvaises conflits de fusion à la fois. Ce qui était encore pire, c'est que la Subversion utilisé les deux sens de la fusion par défaut, ce qui a certains paralysant limitations en automatique lors de la fusion de deux chefs de direction ne sont pas par rapport à leur ancêtre commun.

Pour atténuer cette Subversion maintenant des magasins de méta-données de la direction générale et de fusion. Qui permettrait de résoudre tous les problèmes de droit?

Et oh, en passant, la Subversion suce toujours...

Sur un système centralisé, comme subversion, répertoires virtuels sucer. Pourquoi? Parce que tout le monde a accès à la vue... même les ordures les plus expérimentales. La ramification est bon si vous voulez expérimenter , mais vous ne voulez pas voir tout le monde et de leurs tantes de l'expérimentation. C'est grave cognitif de bruit. Les branches plus vous ajoutez, plus la merde que vous allez voir.

Le plus public de succursales que vous avez dans un référentiel le plus il sera difficile de garder une trace de toutes les différentes branches. Donc la question que vous aurez si la branche est en cours de développement ou si il est vraiment mort qui est difficile à dire dans tout centralisé, système de contrôle de version.

La plupart du temps, de ce que j'ai vu, une organisation sera, par défaut, utilisez une grosse branche de toute façon. Ce qui est dommage car qui à son tour va être difficile de garder une trace de l'analyse et la libération des versions, et de tout ce qui est bien vient de la ramification.

Alors, pourquoi sont-DVCS, tels que Git, Mercurial et le Bazar, mieux que la Subversion à la ramification et la fusion?

Il y a une très simple raison: la ramification est un concept de première classe. Il y a pas de répertoires virtuels de par leur conception et les branches sont des objets durs dans DVCS il doit l'être afin de travailler simplement avec la synchronisation des référentiels (c'est à dire push et pull).

La première chose que vous faites lorsque vous travaillez avec un DVCS est de cloner des dépôts git de l' clone, hg de l' clone et bzr de l' branch). Le clonage est conceptuellement la même chose que la création d'une branche dans le contrôle de version. Certains appellent cela la fourche ou de ramification (même si ce dernier est souvent utilisé pour désigner des co-situé branches), mais c'est juste la même chose. Chaque utilisateur exécute leur propre référentiel qui signifie que vous avez une par utilisateur ramification se passe.

La structure de la version est pas un arbre, mais plutôt un graphique à la place. Plus précisément, un graphe dirigé acyclique (DAG, ce qui signifie un graphique qui n'ont pas des cycles). Vous n'avez pas vraiment besoin de s'attarder dans les détails de disponibilité de base de données autre que chaque commit un ou plusieurs parent références (ce que la validation est fondée sur). Les graphiques montrent les flèches entre les révisions dans le sens inverse à cause de cela.

Un exemple très simple de la fusion serait ce; imaginez un référentiel central appelé origin et un utilisateur, d'Alice, de cloner le dépôt de sa machine.

         a…   b…   c…
origin   o<---o<---o
                   ^master
         |
         | clone
         v

         a…   b…   c…
alice    o<---o<---o
                   ^master
                   ^origin/master

Ce qui se passe pendant un clone, c'est que chaque révision est copié à Alice exactement comme ils ont été (qui est validé par l'unique et identifiable de hachage-id), et marque l'endroit où l'origine de branches sont à.

Alice travaille ensuite sur son repo, s'engageant dans son propre référentiel et décide de pousser ses changements:

         a…   b…   c…
origin   o<---o<---o
                   ^ master

              "what'll happen after a push?"


         a…   b…   c…   d…   e…
alice    o<---o<---o<---o<---o
                             ^master
                   ^origin/master

La solution est plutôt simple, la seule chose que l' origin référentiel besoin de faire est de prendre toutes les nouvelles révisions et déplacer la branche de la révision la plus récente (qui git appelle "fast-forward"):

         a…   b…   c…   d…   e…
origin   o<---o<---o<---o<---o
                             ^ master

         a…   b…   c…   d…   e…
alice    o<---o<---o<---o<---o
                             ^master
                             ^origin/master

Les cas d'utilisation, j'ai illustré ci-dessus, n'a même pas besoin de fusionner rien. Donc, la question n'est pas vraiment avec la fusion des algorithmes depuis trois voies de l'algorithme de fusion est à peu près la même entre tous les systèmes de contrôle de version. La question est plus sur la structure que rien.

Alors, comment vous me montrer un exemple qui a une véritable fusion?

Certes, l'exemple ci-dessus est très simple d'utilisation, donc permet de faire beaucoup plus tordu, un seul même si elle est plus commune. Rappelez-vous que origin a commencé avec trois révisions? Eh bien, le gars qui les a fait, permet de l'appeler Bob, a été travailler sur son propre et faites un commit sur son propre référentiel:

         a…   b…   c…   f…
bob      o<---o<---o<---o
                        ^ master
                   ^ origin/master

                   "can Bob push his changes?" 

         a…   b…   c…   d…   e…
origin   o<---o<---o<---o<---o
                             ^ master

Maintenant, Bob ne peut pas pousser ses changements directement à l' origin référentiel. Comment le système détecte que c'est en vérifiant si Bob révisions directement de descentes de origins', qui dans ce cas n'est pas. Toute tentative de push résultat dans le système en disant quelque chose de semblable à "Euh... j'ai peur que peut pas vous laisser faire, Bob."

Alors, Bob a pour tirer, puis de fusionner les modifications (avec git de l' pull; ou hg de l' pull et merge; ou bzr de l' merge). C'est un processus en deux étapes. Bob premier a chercher la nouvelle révisions, dont la copie d'eux comme ils sont de l' origin référentiel. Nous pouvons maintenant voir que le graphe diverge:

                        v master
         a…   b…   c…   f…
bob      o<---o<---o<---o
                   ^
                   |    d…   e…
                   +----o<---o
                             ^ origin/master

         a…   b…   c…   d…   e…
origin   o<---o<---o<---o<---o
                             ^ master

La deuxième étape du processus d'extraction est de fusionner les divergences de conseils et de faire un commit du résultat:

                                 v master
         a…   b…   c…   f…       1…
bob      o<---o<---o<---o<-------o
                   ^             |
                   |    d…   e…  |
                   +----o<---o<--+
                             ^ origin/master

J'espère que la fusion ne fonctionne pas dans les conflits (si vous prévoyez d'eux, vous pouvez faire les deux étapes manuellement dans git avec fetch et merge). Ce qui plus tard doit être fait est de pousser ces changements de nouveau à l' origin, ce qui résultera en une avance rapide de fusion depuis la fusion s'engager est un descendant direct de la dernière dans l' origin référentiel:

                                 v origin/master
                                 v master
         a…   b…   c…   f…       1…
bob      o<---o<---o<---o<-------o
                   ^             |
                   |    d…   e…  |
                   +----o<---o<--+

                                 v master
         a…   b…   c…   f…       1…
origin   o<---o<---o<---o<-------o
                   ^             |
                   |    d…   e…  |
                   +----o<---o<--+

Il est une autre option pour fusionner dans git et hg, appelé rebase, qui vais passer les changements de Bob après modifications les plus récentes. Depuis que je ne veux pas de cette réponse pour être plus détaillé, je vous laisse lire le git, mercurial ou bazar docs sur la place.

Comme un exercice pour le lecteur, essayez d'établir comment il va travailler avec une participation de l'utilisateur. De même, il est fait comme dans l'exemple ci-dessus avec Bob. La fusion entre les dépôts est plus facile que vous pourriez penser, parce que toutes les révisions/commits sont uniquement identifiable.

Il y a aussi la question de l'envoi de correctifs entre chaque développeur, qui a été un énorme problème dans la Subversion qui est atténuée dans git, hg et bzr par uniquement identifiables révisions. Une fois que quelqu'un a fusionné ses modifications (commit de fusion) et l'envoie pour tout le monde dans l'équipe de consommer soit en le poussant à un référentiel central ou envoyer des correctifs alors qu'ils n'ont pas à vous soucier de la fusion, parce que cela s'est déjà produit. Martin Fowler appelle cette manière de travailler de la promiscuité de l'intégration.

Parce que la structure est différente de la Subversion, en employant un DAG, il permet le branchement et la fusion à faire d'une manière plus facile non seulement pour le système, mais pour l'utilisateur.

29voto

Andrew Aylett Points 16469

Historiquement, la Subversion n'a été en mesure d'effectuer une droite à deux voies de fusion parce que c'est de ne pas stocker toutes les informations de fusion. Il s'agit de prendre une série de changements et de les appliquer à un arbre. Même avec les informations de fusion, c'est encore le plus couramment utilisé de fusion de la stratégie.

Git utilise un 3-way algorithme de fusion par défaut, ce qui implique de trouver un ancêtre commun à la têtes de les fusionner et de faire usage de la connaissance qui existe sur les deux côtés de la fusion. Cela permet à Git d'être plus intelligent pour éviter les conflits.

Git a aussi sophistiqués renommer trouver le code, ce qui aide aussi. Il n'est pas de stocker des ensembles de modifications ou de stocker les informations de suivi -- c'est juste les magasins de l'état des fichiers à chaque commit et utilise des heuristiques pour localiser renomme et le code des mouvements (le stockage sur disque est plus compliqué que cela, mais l'interface de la couche logique expose pas de suivi).

17voto

Andreas Krey Points 1109

Simplement dit, la fusion de la mise en œuvre se fait de mieux dans Git que dans le SVN. Avant de 1,5 SVN n'a pas enregistré une action de fusion, de sorte qu'il était incapable de faire des fusions futures sans l'aide par l'utilisateur, qui doit fournir des informations qui SVN n'a pas d'enregistrement. Avec la version 1.5, il a de mieux, et en effet le SVN de stockage modèle est légèrement plus capable que Git du DAG. Mais SVN stockées les informations de fusion dans une situation assez compliquée formulaire qui permet fusionne prendre massivement plus de temps que dans Git - j'ai observé des facteurs de 300 en temps d'exécution.

Aussi, SVN prétend piste renomme à l'aide fusionne des fichiers déplacés. Mais en réalité, il stocke toujours comme une copie et suppression d'action, et l'algorithme de fusion encore trébuche sur eux dans modifier/renommer des situations, qui est, d'où un fichier est modifié sur une branche et d'un changement de nom sur l'autre, et les branches doivent être fusionnées. De telles situations se produisent encore de fausses conflits de fusion, et dans le cas de répertoire renomme même conduit à silencieux perte de modifications. (Le SVN gens ont alors tendance à souligner que les modifications sont toujours dans l'histoire, mais cela n'aide pas beaucoup quand ils ne sont pas un résultat de la fusion de l'endroit où ils doivent apparaître.

Git, d'autre part, ne prend même pas la piste renomme mais les chiffres après le fait (lors de la fusion du temps), et n'a donc à peu comme par magie.

Le SVN merge représentation a aussi des questions; dans 1.5/1.6 vous pouvez fusionner à partir du tronc de la direction générale aussi souvent que juste aimé, automatiquement, mais une fusion dans l'autre sens devait être annoncé (--reintegrate), et à gauche la direction générale dans un état inutilisable. Beaucoup plus tard, ils ont découvert que ce n'est pas vraiment le cas, et que a) l' --reintegrate peut être déduit automatiquement, et b) reprise des fusions dans les deux directions sont possibles.

Mais après tout cela (ce qui à mon humble avis montre un manque de compréhension de ce qu'ils font), je serais (OK, je suis) très précautions pour l'utilisation de SVN dans toute triviale ramification scénario, et l'idéal serait d'essayer de voir ce que Git pense le résultat de la fusion.

D'autres points soulevés dans les réponses, comme l'a forcé une visibilité globale des branches SVN, ne sont pas pertinentes pour les capacités de fusion (mais pour l'ergonomie). Aussi, le " Git stocke les modifications alors que SVN magasins (quelque chose de différent)' sont pour la plupart hors sujet. Git sur le plan conceptuel magasins de chacun de s'engager en tant que distinct de l'arbre (comme un tar fichier), puis utilise quelques heuristiques pour stocker de façon efficace. Le calcul de l'évolution entre deux commits est séparé de l'espace de stockage mise en œuvre. Ce qui est vrai est que Git stocke l'histoire DAG est beaucoup plus simple que SVN fait de son mergeinfo. Toute personne qui cherche à comprendre ce dernier saura ce que je veux dire.

En un mot: Git utilise une méthode beaucoup plus simple de modèle de données pour stocker les révisions que SVN, et donc il pourrait mettre beaucoup d'énergie dans la fusion des algorithmes plutôt que d'essayer de faire face avec la représentation => pratiquement mieux la fusion.

11voto

daniel kullmann Points 2619

Une chose qui n'a pas été mentionné dans les autres réponses, et c'est vraiment un grand avantage d'un DVCS, c'est que vous pouvez s'engager localement avant de vous pousser vos modifications. SVN, quand j'ai eu un peu de changement, je voulais vérifier, et quelqu'un avait déjà fait un commit sur la même branche dans le temps, cela signifiait que je devais faire un svn update avant que j'ai pu commettre. Cela signifie que mes modifications, et les changements de l'autre personne sont maintenant mélangés ensemble, et il n'y a aucun moyen d'annuler la fusion ( git reset ou hg update -C), parce qu'il n'y est pas de s'engager à revenir. Si la fusion est non-trivial,cela signifie que vous ne pouvez pas continuer à travailler sur votre fonction avant d'avoir nettoyé le résultat de la fusion.

Mais alors, peut-être que c'est seulement un avantage pour les personnes qui sont trop con pour utiliser les branches distinctes (si je me souviens bien, nous avons eu une seule branche qui a été utilisé pour le développement de l'entreprise dans laquelle j'ai utilisé SVN).

10voto

Peter Points 479

J'ai lu la accepté de répondre. C'est tout simplement faux.

SVN fusion peut être une douleur, et il peut également être lourde. Mais, ignorer comment il fonctionne réellement pour une minute. Il n'y a pas d'information que Git ou de garde peut dériver que SVN n'est pas aussi garder ou peuvent en tirer. Plus important encore, il n'y a pas de raison de garder séparé (parfois partielle) des copies de la version système de contrôle sera de vous fournir plus d'informations réelles. Les deux structures sont tout à fait équivalents.

Supposons que vous voulez faire "astucieux chose" Git est "mieux". Et vous êtes chose est vérifié dans le SVN.

Convertir votre SVN en l'équivalent Git formulaire, de le faire dans Git, puis vérifier le résultat, peut-être à l'aide de plusieurs commits, des branches. Si vous pouvez imaginer un moyen automatisé pour tourner un SVN problème dans un Git problème, Git n'a pas d'avantage fondamental.

À la fin de la journée, n'importe quel système de contrôle de version me permettra de

1. Generate a set of objects at a given branch/revision.
2. Provide the difference between a parent child branch/revisions.

En outre, pour la fusion, il est aussi utile (ou critique) pour en savoir

3. The set of changes have been merged into a given branch/revision.

Mercurial, Git et Subversion (désormais nativement, précédemment à l'aide d'svnmerge.py) peuvent tous fournir tous les trois morceaux de l'information. Afin de démontrer quelque chose de fondamentalement mieux avec DVC, s'il vous plaît signaler une quatrième morceau de l'information qui est disponible dans Git/Mercurial/DVC pas disponible sur le SVN / centralisé VC.

Cela ne veut pas dire qu'ils ne sont pas meilleurs outils!

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