56 votes

Comment Git résout-il le problème de la fusion ?

SVN a facilité le branchement en rendant les branches vraiment bon marché, mais les fusions restent un vrai problème dans SVN - un problème que Git est censé résoudre.

Git y parvient-il, et comment ?

(disclaimer : Tout ce que je sais sur Git est basé sur la conférence de Linus - total git noob here)

76voto

VonC Points 414372

Git n'empêchera pas les conflits dans les fusions mais peut réconcilier les historiques même s'ils ne partagent aucun ancêtre parent.
(par Le fichier des greffons ( .git/info/grafts ) qui est une liste, une par ligne, d'un commit suivi de ses parents, que vous pouvez modifier dans ce but de "réconciliation").
C'est assez puissant comme ça.

Mais pour vraiment avoir un aperçu de "la façon dont les fusions ont été pensées", il faut peut commencer par se tourner vers Linus lui-même et réaliser que ce n'est pas tant une question d'"algorithme" :

Linus : Moi personnellement Je veux avoir quelque chose qui soit très facile à répéter et à utiliser. Quelque chose que je comprends o me dit qu'il ne peut pas le faire.
Et très franchement, la fusion de l'historique d'un seul fichier sans prendre en compte l'historique de tous les autres dossiers me fait faire "ugh".

La partie importante d'une fusion n'est pas la façon dont elle gère les conflits (qui doivent de toute façon être vérifiés par un humain s'ils sont un tant soit peu intéressants), mais le fait qu'elle fusionne correctement l'historique afin de disposer d'une nouvelle base solide pour les futures fusions.

En d'autres termes, la partie importante est le trivial partie : le fait de nommer les parents, et de garder trace de leur relation. Pas les heurts.

Et il semble que 99 % des personnes chargées de la gestion de la chaîne d'approvisionnement pensent que la solution à ce problème consiste à faire preuve de plus d'ingéniosité dans les fusions de contenu. Ce qui passe complètement à côté de l'essentiel.


Ainsi, Wincent Colaiuta ajoute (c'est moi qui souligne) :

Il n'y a pas besoin de métadonnées fantaisistes, de suivi des renommages, etc.
La seule chose que vous devez stocker est l'état de l'arbre avant et après chaque modification.

Quels fichiers ont été renommés ? Lesquels ont été copiés ? Lesquels ont été supprimés ? Quelles lignes ont été ajoutées ? Lesquelles ont été supprimées ? Quelles lignes ont été modifiées à l'intérieur ? Quels blocs de texte ont été copiés d'un fichier à l'autre ?
Vous ne devriez pas avoir à vous soucier de ces questions et vous ne devriez certainement pas avoir à conserver des données de suivi spéciales pour vous aider à y répondre : tous les changements apportés à l'arbre (ajouts, suppressions, renommages, modifications, etc.) sont implicitement encodés dans le delta entre les deux états de l'arbre. ; vous venez piste qu'est-ce que le contenu .

Absolument tout peut (et doit) être déduit. .

Git brise le moule parce qu'il pense au contenu, pas aux fichiers.
Il ne suit pas les renommages, il suit le contenu. Et il le fait au niveau de l'arbre entier.
C'est un changement radical par rapport à la plupart des systèmes de contrôle de version.
Il ne prend pas la peine d'essayer de stocker les historiques par fichier ; il stocke plutôt l'historique au niveau de l'arbre.
Lorsque vous effectuez un diff, vous comparez deux arbres, et non deux fichiers.

L'autre décision de conception fondamentalement intelligente est la façon dont Git effectue les fusions.
Les algorithmes de fusion sont intelligents mais ils n'essaient pas d'être trop intelligents. Les décisions sans ambiguïté sont prises automatiquement, mais en cas de doute, c'est à l'utilisateur de décider.
C'est comme ça que ça doit être. Vous ne voulez pas qu'une machine prenne ces décisions pour vous. Vous ne le voudrez jamais.
C'est l'idée fondamentale de l'approche de Git en matière de fusion : alors que tous les autres systèmes de contrôle de version essaient de devenir plus intelligents, Git se décrit volontiers comme le "gestionnaire de contenu stupide", et il est meilleur pour cela.

18voto

Jakub Narębski Points 87537

Il est maintenant généralement admis que l'algorithme de fusion à 3 voies (peut-être avec des améliorations telles que la détection des renommages et le traitement d'un historique plus compliqué), qui prend en compte la version de la branche actuelle ('la nôtre'), la version de la branche fusionnée ('la leur'), et la version de l'ancêtre commun des branches fusionnées ('l'ancêtre') est (d'un point de vue pratique) la meilleure façon de résoudre les fusions. Dans la plupart des cas, et pour la plupart des contenus, la fusion au niveau de l'arbre (quelle version du fichier prendre) est suffisante ; il est rarement nécessaire de traiter les conflits de contenu, et l'algorithme diff3 est alors suffisant.

Pour utiliser la fusion à trois, vous devez connaître l'ancêtre commun des branches fusionnées (appelé aussi base de fusion). Pour cela, vous devez connaître complet l'histoire entre ces branches. Ce qui manquait à Subversion avant la version (actuelle) 1.5 (sans outils tiers comme SVK ou svnmerge), c'était suivi des fusions c'est-à-dire qu'il faut se rappeler pour chaque commit de fusion quels parents (quels commits) ont été utilisés dans la fusion. Sans cette information, il n'est pas possible de calculer correctement l'ancêtre commun en présence de fusions répétées.

Prenez en compte le schéma suivant :

---.---a---.---b---d---.---1
        \        /
         \-.---c/------.---2

(qui sera probablement maltraité... ce serait bien d'avoir la possibilité de dessiner des diagrammes ASCII-art ici) .
Lorsque nous avons fusionné les commits 'b' et 'c' (créant le commit 'd'), l'ancêtre commun était le point de branchement, le commit 'a'. Mais lorsque nous voulons fusionner les commits '1' et '2', l'ancêtre commun est maintenant le commit 'c'. Sans le stockage des informations de fusion, nous devrions conclure à tort que c'est le commit 'a'.

Subversion (avant la version 1.5), et les versions antérieures de CVS, rendaient la fusion difficile parce que vous deviez calculer vous-même l'ancêtre commun, et donner des informations sur l'ancêtre manuellement lors d'une fusion.

Git stocke des informations sur tous les parents d'un commit (plus d'un parent dans le cas d'un commit de fusion) dans l'objet commit. De cette façon, on peut dire que Git stocke le DAG (direct acyclic graph) des révisions, en stockant et en se souvenant des relations entre les commits.


(Je ne suis pas sûr de la façon dont Subversion traite les problèmes mentionnés ci-dessous).

En outre, la fusion dans Git peut traiter deux problèmes de complication supplémentaires : renommage de fichiers (lorsqu'une partie a renommé un fichier, et que l'autre ne l'a pas fait ; nous voulons obtenir le renommage, et nous voulons que les changements soient appliqués au bon fichier) et fusions croisées (histoire plus compliquée, lorsqu'il y a plus d'un ancêtre commun).

  • Renommages de fichiers pendant la fusion sont gérés en utilisant un score de similarité heuristique (la similarité du contenu du fichier et celle du nom du chemin d'accès sont prises en compte). détection de renommage . Git détecte quels fichiers correspondent les uns aux autres dans les branches fusionnées (et les ancêtres). En pratique, cela fonctionne assez bien pour les cas réels.
  • Fusions croisées voir définition au wiki revctrl.org (et présence de bases de fusion multiples ) sont gérés en utilisant stratégie de fusion récursive ce qui génère un seul ancêtre commun virtuel.

9voto

jdwyah Points 568

Les réponses ci-dessus sont toutes correctes, mais je pense qu'elles manquent le point central des fusions faciles de git pour moi. Une fusion SVN nécessite de garder la trace et de se souvenir de ce qui a été fusionné et c'est un énorme PITA. Extrait de leur documentation :

svn merge -r 23:30 file:///tmp/repos/trunk/vendors

Maintenant, ce n'est pas mortel, mais si vous oubliez si c'est 23-30 inclus ou 23-30 exclusifs, ou si vous avez déjà fusionné certains de ces commits, vous êtes fichu et vous devez trouver les réponses pour éviter de répéter ou de manquer des commits. Que Dieu vous aide si vous faites une branche.

Avec git, il suffit de git merge et tout cela se passe de manière transparente, même si vous avez sélectionné quelques commits ou fait un certain nombre de choses fantastiques dans git-land.

5voto

hillu Points 4033

Pour autant que je sache, les algorithmes de fusion ne sont pas plus intelligents que ceux des autres systèmes de contrôle de version. Cependant, en raison de la nature distribuée de git, il n'est pas nécessaire de centraliser les efforts de fusion. Chaque développeur peut rebaser ou fusionner les petits changements des autres développeurs dans son arbre à tout moment, et les conflits qui surviennent ont donc tendance à être plus petits.

-9voto

RibaldEddie Points 3113

Git rend simplement plus difficile le fait de bousiller le dépôt de tous les autres avec une mauvaise fusion.

Le seul avantage réel est que Git est beaucoup, beaucoup plus rapide à fusionner parce que tout est fait localement et que c'est écrit en C.

SVN, utilisé correctement, est parfaitement utilisable.

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