web-dev-qa-db-fra.com

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

SVN a fait de la ramification beaucoup plus facile en faisant des succursales vraiment bon marché, mais la fusion reste un véritable problème dans SVN - celui qui git résolument résolver.

Git l'atteint-il et comment?

(Disclaimer: Tout ce que je sais sur Git est basé sur la conférence Linus - Total Git Noob ici)

56
Assaf Lavie

Git n'empêchera pas les conflits dans la fusion mais peut réconcilier l'histoire même lorsqu'elles ne partagent pas d'ancêtre parent.
[.____] (à travers le fichier de greffes (.git/info/grafts) , qui est une liste, une par ligne, d'un commit suivie de ses parents, que vous pouvez modifier pour cette "réconciliation".)
Si assez puissant droit là-bas.

Mais pour avoir un aperçu de "Comment des fantasmes ont été réfléchies à travers", vous peut commencer par se tourner vers Linus lui-même et réalisez que ce problème n'est pas tant de "algorithme":

linus: ME Personnellement, je veux avoir quelque chose qui est très répétable et non intelligent. Quelque chose que je comprends ou me dit que cela ne peut pas le faire.
[.____] et franchement, la fusion de l'historique des fichiers mono-file Sans Prendre tout l'historique des autres fichiers en compte me fait partir "Ugh".

La partie importante d'une fusion n'est pas la manière dont il gère les conflits (qui doivent être vérifiés par un humain quand ils sont du tout intéressant), mais qu'il devrait fondre l'histoire ensemble de sorte que Vous avez une nouvelle base solide pour les fantasmes futurs.

En d'autres termes, la partie importante est le trivial Partie: la nommée des parents et en gardant une trace de leur relation. Pas les affrontements.

Et cela ressemble à 99% des personnes SCM semblent penser que la solution à cela doit être plus intelligente sur la fusion de contenu. Qui manque entièrement le point.


Alors Wincent Colaiuta ajoute (emphasis mine):

Il n'ya pas besoin de métadonnées de fantaisie, de suivi de renommée et ainsi de suite.
[.____] La seule chose que vous devez stocker est l'état de l'arbre avant et après chaque changement.

Quels fichiers ont été renommés? Lesquels ont été copiés? Lesquels ont été supprimés? Quelles lignes ont été ajoutées? Lesquels ont été supprimés? Quelles lignes avaient des changements fabriqués à l'intérieur d'eux? Quelles dalles de texte ont été copiées d'un fichier à un 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 afin de vous aider à vous répondre: toutes les modifications apportées à L'arbre (ajouts, suppressions, renomes, modifications, etc.) sont implicitement codés dans le delta entre les deux états de l'arborescence ; vous venez piste Quel est le contenu.

absolument tout peut (et devrait) être déduit .

Git brise le moule car il pense au contenu, pas de fichiers.
[.____] Cela ne suit pas la renommée, il suit le contenu. Et cela le fait à un niveau d'arbre entier.
[.____] Il s'agit d'un départ radical de la plupart des systèmes de contrôle de version.
[.____] Cela ne tente pas d'essayer de stocker des histoires par fichier; Il stocke plutôt l'histoire au niveau de l'arbre.
[.____] Lorsque vous effectuez une diff, vous comparez deux arbres, pas deux fichiers.

L'autre décision de conception fondamentalement intelligente est la fusion de GIT.
[.____] Les algorithmes de fusion sont intelligents mais ils n'essayent pas d'être trop intelligents. Les décisions sans ambiguïté sont fabriquées automatiquement, mais quand il y a des doutes, il appartient à l'utilisateur de décider.
Ceci est la façon dont il devrait être. Vous ne voulez pas une machine faisant ces décisions pour vous. Vous ne le voudriez jamais.
[.

76
VonC

Il est maintenant généralement d'accord sur cet algorithme de fusion 3 voies (peut-être avec des améliorations telles telles que la détection de changement de nom et de traiter l'histoire plus compliquée), qui prend en version compte sur la branche actuelle ( " les nôtres "), la version sur la branche issue de la fusion ( " leur " ), et la version de l'ancêtre commun des branches fusionnées ( " ancêtre ") est (du point de vue pratique) la meilleure façon de résoudre les fusions de. Dans la plupart des cas, et pour la plupart de la fusion de niveau de l'arborescence de contenu (version de fichier à prendre) est suffisant; il est rarement nécessaire pour faire face aux conflits de contenu, puis l'algorithme diff3 est assez bon.

Pour utiliser la fusion 3 voies dont vous avez besoin de connaître ancêtre commun des branches fusionnées (co appelée de base de fusion). Pour cela, vous devez savoir histoire complète entre ces branches. Qu'est-ce que Subversion avant la version (actuelle) 1,5 a fait défaut (sans outils tiers tels comme SVK ou svnmerge) était suivi de fusion, à savoir se souvenir de ce commit de fusion les parents (ce qui engage) ont été utilisés dans la fusion. Sans cette information, il est impossible de calculer correctement ancêtre commun en présence de fusions répétées.

Prenez pour le compte du schéma suivant:

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

(qui probablement se mutilée ... ce serait bien d'avoir la capacité de dessiner des diagrammes-art ASCII ici).
Quand nous fusionnons 'b' commits et 'c' (création commit 'd'), l'ancêtre commun a été le point de branchement, commit 'a'. Mais quand on veut fusionner commits " 1 " et " 2 ", maintenant l'ancêtre commun est commit " c ". Sans stocker des informations de fusion, nous aurions tort de conclure qu'il est engage " a ".

Subversion (avant la version 1.5) et CVS plus tôt, fit fusionner dur car il fallait calculer vous-même ancêtre commun, et donner des informations sur l'ancêtre manuellement lorsque vous effectuez une fusion.

Stocke les informations Git sur tous les parents d'un commit (plus d'un parent dans le cas de fusion commit) dans l'objet commit. De cette façon, vous pouvez dire que Git stocke DAG (graphique acyclique directe) de révisions, le stockage et se rappelant les relations entre les commits.


(Je ne suis pas sûr de savoir comment traite Subversion avec les problèmes mentionnés ci-dessous)

En outre la fusion dans Git peut faire face à deux problèmes de complication supplémentaire: fichier renomme (quand un côté renommé un fichier, et d'autres ne l'a pas, nous voulons renommage, et nous voulons obtenir des changements appliqués au fichier correct) et Sillonnez se confond (histoire plus compliquée, quand il y a plus d'un ancêtre commun).

  • renommages de fichiers lors de la fusion sont gérées à l'aide score de similitude heuristique basée (à la fois similitude des contenus de fichiers et la similitude des pathname est pris en compte) Rename détection. Git Détecte quels fichiers correspondent les uns aux autres dans les branches fusionnées (et ancêtre (s)). Dans la pratique, cela fonctionne très bien pour les affaires du monde réel.
  • entrecroisées fusions , voir définition à revctrl.org wiki , (et en présence de plusieurs bases de fusion ) sont gérés à l'aide stratégie récursive de fusion, qui génère ancêtre commun virtuel unique.
18
Jakub Narębski

Les réponses ci-dessus sont toutes correctes, mais je pense qu'ils manquent le point central de la fusion facile de Git pour moi. Une fusion SVN vous oblige à garder une piste et souvenez-vous de ce qui a été fusionné et c'est un énorme pita. De leurs documents:

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

Maintenant que ce n'est pas tueur, mais si vous oubliez s'il est 33-30 inclus ou 23-30 exclusif, ou si vous avez déjà fusionné certaines de ces commits, vous êtes hosté et vous devez aller comprendre les réponses à éviter répéter ou manquant commet. Dieu vous aide si vous branchez une branche.

Avec Git, il s'agit juste de git fusion et tout cela se produit de manière transparente, même si vous avez choisi un couple comme un couple ou fait un certain nombre de choses fantastiques git-terre.

9
jdwyah