tortoise tag entre diferencia create crear branches svn git version-control

tag - git-svn download



¿Cómo resuelve Git el problema de la fusión? (5)

SVN hizo la bifurcación mucho más fácil al hacer las sucursales realmente baratas, pero las fusiones siguen siendo un problema real en SVN, una que Git supuestamente resuelve.

¿Git logra esto y cómo?

(Descargo de responsabilidad: Todo lo que sé sobre Git se basa en la conferencia de Linus - total novato git aquí)


Ahora se acordó generalmente en ese algoritmo de combinación de 3 vías (quizás con mejoras tales como la detección de renombrado y el manejo de la historia más complicada), 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 utilizar la combinación de 3 vías, necesita conocer el antecesor común de las ramas fusionadas (co llamado fusionar base). Para esto, necesitas saber la historia completa entre esas ramas. Lo que faltaba antes de Subversion (actual) versión 1.5 (sin herramientas de terceros como SVK o svnmerge) era el seguimiento de fusión , 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.

Tome en cuenta el siguiente diagrama:

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

(que probablemente se rompa ... sería bueno tener la capacidad de dibujar diagramas ASCII-art 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, hicieron la fusión difícil porque usted tuvo que calcular antecesor común usted mismo, y brindar 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) 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 aborda los problemas mencionados a continuación)

Además, la fusión en Git puede resolver dos problemas adicionales: el cambio de nombre de los archivos (cuando un lado renombró un archivo y el otro no, queremos cambiar el nombre y queremos aplicar los cambios al archivo correcto) y las fusiones entrecruzadas (historia más complicada, cuando hay más de un antepasado común).

  • El cambio de nombre de los archivos durante la fusión se gestiona utilizando una puntuación de similitud heurística basada (se tiene en cuenta la similitud de los contenidos del archivo y la similitud de la ruta) 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.
  • Las fusiones entrecruzadas , consulte la definición en la wiki de revctrl.org (y la presencia de varias bases de combinación ) se gestionan mediante el uso de la estrategia de fusión recursiva , que genera un ancestro virtual común único.

Git solo hace que sea más difícil arruinar el repositorio de todos los demás con una mala fusión.

El único beneficio real es que Git es mucho, mucho más rápido en fusionarse porque todo se hace localmente y está escrito en C.

SVN, utilizado correctamente, es perfectamente utilizable.


Hasta donde yo sé, los algoritmos de fusión no son más inteligentes que los de otros sistemas de control de versiones. Sin embargo, debido a la naturaleza distribuida de git, no hay necesidad de esfuerzos de fusión centralizados. Cada desarrollador puede reubicar o fusionar pequeños cambios de otros desarrolladores en su árbol en cualquier momento, por lo tanto, los conflictos que surgen tienden a ser más pequeños.


Las respuestas anteriores son todas correctas, pero creo que pierden el punto central de las fáciles fusiones de git para mí. Una fusión de SVN requiere que haga un seguimiento y recuerde qué se ha fusionado y eso es un gran PITA. De sus documentos:

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

Ahora bien, eso no es sorprendente, pero si se olvida de si es 23-30 inclusivo o 23-30 exclusivo, o si ya ha fusionado algunos de esos compromisos, se lo roció y debe encontrar las respuestas para evitarlo. Compromisos repetitivos o faltantes. Dios te ayude si ramas una rama.

Con git es solo una combinación de git y todo esto sucede a la perfección, incluso si has escogido un par de compromisos o has hecho una cantidad de cosas fantásticas de git-land.


Git no evitará el conflicto en las fusiones, pero puede reconciliar la historia incluso cuando no comparten ningún antecesor padre.
(a través del archivo de injertos ( .git/info/grafts ) , que es una lista, uno por línea, de una confirmación seguida de sus padres, que puede modificar para ese propósito de "reconciliación").
Tan poderoso aquí.

Pero para realmente tener una idea de "cómo se han pensado las fusiones", puede comenzar recurriendo a Linus y darse cuenta de que este tema no se trata tanto de "algoritmo":

Linus : Yo personalmente , quiero tener algo que sea muy repetible y no inteligente. Algo que entiendo o me dice que no puede hacerlo.
Y francamente, fusionar el historial de un solo archivo sin tener en cuenta el historial de todos los demás archivos me hace ir "ugh".

La parte importante de una combinación no es cómo maneja los conflictos (que deben ser verificados por un humano de todos modos si son del todo interesantes), sino que debe unir la historia para que tenga una nueva base sólida para futuras fusiones .

En otras palabras, la parte importante es la parte trivial : el nombramiento de los padres y el seguimiento de su relación. No los enfrentamientos

Y parece que el 99% de las personas de SCM parecen pensar que la solución para eso es ser más astutos sobre el contenido. Lo cual pasa por alto el punto por completo.

Entonces Wincent Colaiuta agrega (énfasis mío):

No hay necesidad de metadatos sofisticados, cambiar el nombre de seguimiento, etc.
Lo único que necesita almacenar es el estado del árbol antes y después de cada cambio.

¿Qué archivos fueron renombrados? ¿Cuáles fueron copiados? ¿Cuáles fueron eliminados? ¿Qué líneas se agregaron? ¿Cuáles fueron eliminados? ¿Qué líneas tuvieron cambios dentro de ellas? ¿Qué losas de texto se copiaron de un archivo a otro?
No debería preocuparse por ninguna de estas preguntas y, desde luego, no debería tener que mantener datos de seguimiento especiales para ayudarlo a responderlas: todos los cambios en el árbol (adiciones, eliminaciones, cambios de nombre, ediciones, etc.) son implícitos. codificado en el delta entre los dos estados del árbol ; solo rastreas cuál es el contenido .

Absolutamente todo puede (y debe) inferirse .

Git rompe el molde porque piensa en el contenido, no en los archivos.
No realiza un seguimiento de los cambios de nombre, rastrea el contenido. Y lo hace a nivel de todo un árbol.
Esta es una desviación radical de la mayoría de los sistemas de control de versiones.
No se molesta en intentar almacenar historiales por archivo; en su lugar, almacena la historia en el nivel del árbol.
Cuando realiza un diff, está comparando dos árboles, no dos archivos.

La otra decisión de diseño fundamentalmente inteligente es cómo se fusiona Git.
Los algoritmos de fusión son inteligentes, pero no intentan ser demasiado inteligentes. Las decisiones no ambiguas se toman automáticamente, pero cuando hay dudas, es decisión del usuario.
Esta es la forma en que debería ser. No quiere que una máquina tome esas decisiones por usted. Nunca lo querrás.
Esa es la idea fundamental en el enfoque de Git para la fusión: mientras que cualquier otro sistema de control de versiones intenta ser más inteligente, Git se describe a sí mismo felizmente como el "administrador de contenido estúpido", y es mejor para él.