¿Hay alguna diferencia entre fusiones en svn en comparación con git o mercurial?

12

Según tengo entendido, SVN es 'fácil de ramificar. Difícil de fusionar '. ¿Porqué es eso? ¿Hay alguna diferencia en cómo se fusionan?


fuente

Respuestas:

21

Consulte mi respuesta de desbordamiento de pila para una situación muy concreta en la que Mercurial (y Git) se fusiona sin problemas y donde Subversion le presenta un conflicto falso. La situación es una refactorización simple realizada en una rama donde se cambia el nombre de algunos archivos.

Con respecto a la respuesta de tdammers, hay una serie de malentendidos allí:

  • Subversion, Mercurial y Git siguen todas las instantáneas del proyecto en todo el repositorio. Llamarlos versiones , revisiones o conjuntos de cambios no hace ninguna diferencia. Todas son instantáneas lógicamente atómicas de un conjunto de archivos.

  • El tamaño de sus confirmaciones no hace ninguna diferencia cuando se trata de fusionar. Los tres sistemas se fusionan con el algoritmo de fusión estándar de tres vías y las entradas a ese algoritmo son

    • mayor versión ancestral común
    • versión en una rama
    • versión en otra rama

    No importa cómo se crearon las dos versiones de ramificación. Puede haber usado 1000 pequeñas confirmaciones desde la versión ancestral, o puede haber usado 1 confirmación. Lo único que importa es la versión final de los archivos. (¡Sí, esto es sorprendente! Sí, muchas guías de DVCS se equivocan terriblemente).

También plantea algunos buenos puntos sobre las diferencias:

  • Subversion tiene algo de "vudú" en el que puede fusionarse /trunk, por ejemplo /branches/foo. Mercurial y Git no usan este modelo: las ramas se modelan directamente en el historial. Por lo tanto, la historia se convierte en un gráfico acíclico dirigido en lugar de ser lineal. Este es un modelo mucho más simple que el utilizado por Subversion y esto elimina una serie de casos de esquina.

  • Puede retrasar fácilmente una fusión o incluso dejar que otra persona lo maneje. Si hg mergele da una tonelada de conflictos, puede pedirle a su compañero de trabajo que lo hg pullhaga y luego tiene exactamente el mismo estado. Entonces él puede hg mergey tal vez sea mejor para resolver conflictos que tú.

    Esto es muy difícil con Subversion, donde debe actualizar antes de poder realizar la confirmación. No puede simplemente ignorar los cambios en el servidor y seguir comprometiéndose en su propia rama anónima. En general, Subversion te obliga a jugar con una copia sucia cuando trabajassvn update . Esto es un poco arriesgado ya que no ha almacenado sus cambios en ningún lugar seguro. Git and Mercurial te permite confirmar primero, y luego actualizar y combinar según sea necesario.

La verdadera razón por la que Git y Mercurial son mejores para la fusión que Subversion es una cuestión de implementación. Hay conflictos de cambio de nombre que Subversion simplemente no puede manejar, incluso si está claro cuál es la respuesta correcta. Mercurial y Git los manejan fácilmente. Pero no hay ninguna razón por la que Subversion no pueda manejarlos también: estar centralizado ciertamente no es la razón.

Martin Geisler
fuente
44
¡gran respuesta! Votaría dos veces si pudiera. :) También agregaría que el libro SVN al que se refiere en la respuesta SO admite claramente que "la función de seguimiento de fusión de Subversion tiene una implementación interna extremadamente compleja ..." - esto solo es una muy buena indicación de que la característica no es confiable
gnat
2
... e incluso con esa implementación extremadamente compleja no se puede descubrir correctamente el antepasado común en casos que no sean simples.
Jan Hudec
Acerca de las fusiones retrasadas, no lo entiendo, con SVN, mi compañero de trabajo puede actualizar a / finalizar el enlace troncal y luego fusionarse desde mi rama en él.
Gill Bates
@GillBates: estoy hablando de una situación en la que no ha iniciado una sucursal para su trabajo, cuando está trabajando trunken SVN. Con un DVCS puede comprometerse sin compartir, pero en SVN svn commitafectará directamente a otros que trabajan en la misma rama. Incluso si los dos trabajamos en una sucursal en SVN, no puedo comprometer mi trabajo sin tener que fusionarme inmediatamente con tu trabajo. Eso hace que las confirmaciones sean algo aterradoras, ¡lo cual es una propiedad aterradora para un sistema de control de versiones! :-)
Martin Geisler
6

El problema central radica en la forma en que estos sistemas representan una estructura de directorios versionada.

El concepto básico de Subversion en torno al cual gira todo el sistema es el de una versión (o, en svn lingo, "revisión"): una instantánea de un archivo en un punto determinado. Siempre y cuando el historial sea perfectamente lineal, todo está bien, pero si necesita fusionar los cambios de dos líneas de desarrollo independientes, svn tiene que comparar las versiones actuales de ambos, y luego hacer una comparación de tres vías entre la última versión compartida y las dos versiones principales. Las líneas que aparecen cambiadas en una de las cabezas, pero no en la otra, pueden resolverse fácilmente; las líneas que se desvían exactamente de la misma manera en ambas cabezas son más difíciles, pero generalmente factibles; Las líneas que se desvían de diferentes maneras son lo que hace que svn diga "No puedo resolver esto, humano, por favor resuélvelo por mí".

Por el contrario, git y mercurial rastrean conjuntos de cambios en lugar de versiones. El repositorio completo es un árbol de conjuntos de cambios, cada uno de los cuales depende de un padre, donde un conjunto de cambios padre puede tener cualquier número de hijos, y la raíz del árbol representa un directorio vacío. En otras palabras, git / hg dice "primero no tenía nada, luego se aplicó este parche, luego ese parche, etc.". Cuando necesita fusionar dos líneas de desarrollo, git / hg no solo sabe cómo se ve cada cabeza actualmente, y cómo se veía la última versión común, también sabe cómo sucedió la transición, permitiendo una fusión mucho más inteligente.

Otra cosa que facilita la fusión en un DVCS es una consecuencia indirecta de separar los conceptos de commit y push, y de permitir todo tipo de combinaciones cruzadas entre dos clones del mismo repositorio en cualquier momento. Con svn, las personas tienden a comprometer grandes conjuntos de cambios con cambios a menudo no relacionados, porque una confirmación también es una actualización en el repositorio central que afecta a todos los demás miembros del equipo; si cometes una versión rota, todos se enojarán contigo. Dado que la mayoría de las configuraciones involucran un servidor svn en red, la confirmación también implica el bombeo de datos a través de la red, lo que significa que la confirmación introduce un retraso considerable en el flujo de trabajo (especialmente cuando su copia de trabajo está desactualizada y debe extraerla primero). Con git y mercurial, el commit ocurre localmente, y debido a que ambos son muy eficientes en el manejo de sistemas de archivos locales, generalmente finaliza instantáneamente. Como resultado, las personas (una vez que se acostumbran) cometen pequeños cambios incrementales, y luego, cuando funciona, Empuje una docena de compromisos de una vez Luego, cuando llega el momento de la fusión, el SCM tiene información mucho más detallada, y puede hacer un mejor trabajo resolviendo conflictos de manera segura y automática.

Y luego están los bonitos detalles que hacen las cosas aún más fáciles:

  • Puede tener varias cabezas y aún comprometerse en cualquiera; a diferencia de la subversión, no es necesario combinar extracción, actualización y fusión antes de volver a comprometerse; las múltiples cabezas permanecen así hasta que elija fusionar
  • Los directorios no son tratados especialmente; en cambio, la ruta solo se considera un nombre de archivo grande, y todos sus directorios deben estar en la misma revisión en todo momento. Esto significa que no puede hacer el vudú de subversión donde las subcarpetas de un proyecto están en diferentes revisiones, pero también significa que es menos probable que la copia de trabajo se convierta en un gran desastre roto inmanejable y, lo que es más interesante, un movimiento no se representa como una eliminación -y-add (que se rompería completamente en svn si no fuera por los metadatos de actualización), sino simplemente como un cambio de nombre; si mueve un archivo, se conserva todo su historial; la fusión incluso puede aplicar cambios al archivo movido que se hicieron a una versión no movida del mismo archivo después del movimiento, en otra rama
  • La mayoría de las veces, en realidad ni siquiera necesita ramificarse: en su lugar, solo clona todo el repositorio. La clonación es barata, especialmente si se realiza en el mismo sistema de archivos, y si decide que desea deshacerse del clon, simplemente elimine el directorio en el que vive y eso es todo. Ni siquiera necesita usar hg o git para eso.
  • Existen pocas (si es que hay alguna) restricciones sobre lo que puede combinar. Puede tener seis clones del mismo repositorio y fusionar (o más bien, empujar o tirar; a menudo no se requiere una fusión explícita) de A a B, luego de C a B, luego de B a D, luego de C a D, B hacia atrás a A, D a E, en cualquier momento y con la frecuencia que desee.
  • Puede probar una fusión clonando uno de los repositorios que desea fusionar, y luego presionando desde el otro. Si hace lo que quiere, puede retroceder al objetivo real, si no lo hace, tira el clon y comienza de nuevo.
tdammers
fuente
2
Debo mencionar algunas correcciones y agregar respuestas: 1. Las revisiones de SVN son globales por repositorio , la revisión representa todos los archivos en repos en algún momento 2. La tecnología de fusión es básicamente común en SVN y DVCS - si el archivo en archivos de fusión solo cambió el de la misma manera , la fusión producirá la misma cantidad de conflictos para SVN y DVCS: todos los SCM aún operan en el nivel de cadena, no en un bloque lógico 3. Las grandes confirmaciones en SVN no son resultado de debilidad arquitectónica, sino porque los usuarios a menudo son idiotas perezosos - ignoran los patrones básicos. Branch | merge funciona en SVN, si / dev / brain y / dev / hands funcionan
Lazy Badger
2
Parte 2: la fusión inteligente en DVCS ocurre principalmente porque, al contrario de Subversion, rastrean y manejan los movimientos | cambios de nombre de los archivos y SVN no lo hace en absoluto, por lo tanto, cualquier operación, cuyo archivo de proceso, cambió en un lado y cambió de nombre en segundo, fallará. La ramificación con ramas y la clonación son solo estrategias diferentes de ramificación con los mismos derechos de vida, que usar "... depende de ..."
Lazy Badger
@LazyBadger: Au contraire. La subversión hace pista se mueve / cambia el nombre, lo que provoca conflictos espurios en parte porque es el manejo de los cambios de nombre en fusión es simplemente buggy y en parte porque hay casos de esquina que son difíciles o imposibles de manejar correctamente. La última es la razón por la cual git (y mercurial lo copió) por diseño no rastrea los renombrados y los adivina al fusionarlos. Lo que funciona bien si el contenido sigue siendo lo suficientemente similar como para fusionarse (que es cuando lo necesita) y de lo contrario no hace cosas tontas.
Jan Hudec
@JanHudec - lo siento, el identificador SVN no se mueve | cambia el nombre en una acción atómica (forma DVCS - "renombrar"), pero como "eliminar + ...", por lo tanto - produce conflictos de árbol, donde no sucede en DVCS ( cambio de nombre verdadero ) Mercurial cambia de nombre explícitamente ( hg mvo hg addremove --similarity...), mientras que Git usa heurística, pero ambos manejan los cambios de nombre . ¡Puedo obtener un conflicto de árbol incluso con una diferencia de 1 cadena en los archivos combinados! Tienes que volver a aprender algunos aspectos de Subversion, lo siento.
Lazy Badger
55
Ahora nos estamos volviendo bastante técnicos :-) Copias de pistas de Subversion y Mercurial , no cambios de nombre. Ambos sistemas rastrean rename a bcomo copy a b; remove ay ambos lo hacen en una confirmación atómica. La diferencia en el comportamiento de fusión se debe al manejo diferente de los casos de esquina y a que Subversion permite más fusiones que Mercurial y Git. Finalmente, Git detecta los cambios de nombre en el momento de la fusión y el registro; estamos pensando en agregar esto también en Mercurial.
Martin Geisler