Ahora se acepta generalmente ese algoritmo de fusión tridireccional (quizás con mejoras tales como detección de renombrado y manejo de historial más complicado), que tiene en cuenta la versión en la rama actual ('nuestra'), versión en La rama fusionada ('theirs'), y la versión del ancestro común de las ramas fusionadas ('ancestro') es (desde el punto de vista práctico) la mejor forma de resolver las fusiones. En la mayoría de los casos, y para la mayoría de los contenidos, la fusión de nivel de árbol (qué versión de archivo tomar) es suficiente; rara vez es necesario tratar con conflictos de contenido, y entonces el algoritmo diff3 es lo suficientemente bueno.
Para usar la combinación de 3 vías, necesita conocer el antecesor común de las ramas fusionadas (co llamado fusionar base). Para esto necesita saber completo historial entre esas ramas. Lo que faltaba antes de Subversion (versión actual) 1.5 (sin herramientas de terceros como SVK o svnmerge) era merge tracking, es decir, recordar para fusionar confirmar qué padres (qué confirma) se usaron en la fusión. Sin esta información, no es posible calcular correctamente el antecesor común en presencia de fusiones repetidas.
Toma para la cuenta el siguiente diagrama:
---.---a---.---b---d---.---1
\ /
\-.---c/------.---2
(lo que probablemente conseguir destrozado ... sería bueno tener capacidad de dibujar diagramas del arte ASCII aquí).
Cuando estábamos fusionando commits 'b' y 'c' (creando commit 'd'), el antecesor común era el punto de bifurcación, commit 'a'. Pero cuando queremos combinar commits '1' y '2', ahora el antecesor común es commit 'c'. Sin almacenar la información de fusión, tendríamos que concluir erróneamente que es commit 'a'.
Subversion (anterior a la versión 1.5), y CVS anterior, fusionó duro porque tenía que calcular antepasado común usted mismo, y proporcionar información acerca del antecesor manualmente al hacer una fusión.
Git almacena información sobre todos los padres de una confirmación (más de un padre en el caso de la fusión de confirmación) en el objeto de confirmación. De esta forma, puede decir que Git almacena DAG (gráfico acíclico directo) de revisiones, almacenando y recordando las relaciones entre commits.
(no estoy seguro de cómo Subversion trata las cuestiones que se mencionan a continuación)
Adicionalmente se fusionan en Git pueden hacer frente a dos problemas de complicaciones adicionales: archivo renombra (cuando un lado a llamarse un archivo , y otros no; queremos obtener un cambio de nombre, y queremos que se apliquen los cambios al archivo correcto) y se fusiona cruzada (historial más complicado, cuando hay más de un antepasado común).
- del archivo cambia el nombre de durante la fusión se gestionan mediante puntuación de similitud basado en heurística (ambos similitud del contenido del archivo y la similitud de nombre de ruta se tiene en cuenta) detección de cambio de nombre. Git detecta qué archivos se corresponden entre sí en ramas fusionadas (y ancestros). En la práctica, funciona bastante bien para casos del mundo real.
- Criss-cross fusiona, ver definition at revctrl.org wiki, (y la presencia de múltiples bases de combinación de) se gestionan mediante el uso de estrategia de combinación recursiva, que genera único ancestro común virtual.
En respuesta a: "SVN hizo la bifurcación mucho más fácil haciendo que las ramas fueran realmente baratas". ¿Estás seguro de que no reemplazaste accidentalmente a Git con SVN? Sé que una de las características principales que Git presume es la ramificación barata ... He oído que la ramificación en SVN es una pesadilla porque gran parte de ella es manual (crea un nuevo directorio con contenido ramificado, etc.). – Stunner