A menudo leo que Hg (y Git y ...) son mejores para fusionarse que SVN, pero nunca he visto ejemplos prácticos de dónde Hg / Git puede fusionar algo donde SVN falla (o donde SVN necesita intervención manual). ¿Podría publicar algunas listas paso a paso de ramas / modificar / confirmar / ... operaciones que muestren dónde SVN fallaría mientras Hg / Git felizmente avanza? Casos prácticos, no muy excepcionales, por favor ...
Algunos antecedentes: tenemos unas pocas docenas de desarrolladores trabajando en proyectos usando SVN, con cada proyecto (o grupo de proyectos similares) en su propio repositorio. Sabemos cómo aplicar versiones de lanzamiento y características para no tener problemas muy a menudo (es decir, hemos estado allí, pero hemos aprendido a superar los problemas de Joel de "un programador que causa trauma a todo el equipo") o "necesita seis desarrolladores durante dos semanas para reintegrar una sucursal"). Tenemos ramas de lanzamiento que son muy estables y solo se utilizan para aplicar correcciones de errores. Tenemos troncales que deberían ser lo suficientemente estables como para poder crear una versión en una semana. Y tenemos ramas de características en las que pueden trabajar los desarrolladores individuales o grupos de desarrolladores. Sí, se eliminan después de la reintegración para que no abarroten el repositorio. ;)
Así que todavía estoy tratando de encontrar las ventajas de Hg / Git sobre SVN. Me encantaría tener algo de experiencia práctica, pero todavía no hay proyectos más grandes que podamos mover a Hg / Git, así que estoy atascado con jugar con pequeños proyectos artificiales que solo contienen algunos archivos inventados. Y estoy buscando algunos casos en los que pueda sentir el impresionante poder de Hg / Git, ya que hasta ahora he leído sobre ellos pero no he podido encontrarlos.
Respuestas:
Yo mismo no uso Subversion, pero según las notas de la versión para Subversion 1.5: Seguimiento de fusión (fundacional) parece que existen las siguientes diferencias con respecto a cómo funciona el seguimiento de fusión en sistemas de control de versiones DAG completos como Git o Mercurial.
Fusionar tronco a rama es diferente de fusionar rama a tronco: por alguna razón, la combinación de tronco a rama requiere la
--reintegrate
opciónsvn merge
.En los sistemas de control de versiones distribuidas como Git o Mercurial no hay diferencia técnica entre troncal y rama: todas las ramas se crean de la misma manera ( aunque puede haber una diferencia social ). La fusión en cualquier dirección se realiza de la misma manera.
Debe proporcionar una nueva opción
-g
(--use-merge-history
)svn log
ysvn blame
tener en cuenta el seguimiento de fusión.En Git y Mercurial, el seguimiento de fusión se tiene en cuenta automáticamente al mostrar el historial (registro) y la culpa. En Git puede solicitar seguir al primer padre solo con
--first-parent
(supongo que existe una opción similar también para Mercurial) para "descartar" la información de seguimiento de fusióngit log
.Por lo que entiendo, la
svn:mergeinfo
propiedad almacena información por ruta sobre conflictos (Subversion está basada en el conjunto de cambios), mientras que en Git y Mercurial es simplemente confirmar objetos que pueden tener más de un padre.La subsección "Problemas conocidos" para el seguimiento de fusión en Subversion sugiere que la fusión repetida / cíclica / reflexiva podría no funcionar correctamente. Significa que con las siguientes historias la segunda fusión podría no hacer lo correcto ('A' puede ser tronco o rama, y 'B' puede ser rama o tronco, respectivamente):
En el caso de que el arte ASCII anterior se rompa: la rama 'B' se crea (bifurca) a partir de la rama 'A' en la revisión 'x', luego la rama 'A' se fusiona en la revisión 'y' en la rama 'B' como fusionar 'M1', y finalmente la rama 'B' se fusiona en la rama 'A' como la combinación 'M2'.
En el caso de que el arte ASCII anterior se rompa: la rama 'B' se crea (bifurca) a partir de la rama 'A' en la revisión 'x', se fusiona en la rama 'A' en 'y' como 'M1', y más tarde se fusionó nuevamente en la rama 'A' como 'M2'.
Es posible que Subversion no admita casos avanzados de fusión entrecruzada .
Git maneja esta situación muy bien en la práctica usando la estrategia de fusión "recursiva". No estoy seguro acerca de Mercurial.
En "Problemas conocidos" , se advierte que el seguimiento de fusión podría no funcionar con los cambios de nombre de archivos, por ejemplo, cuando un lado cambia el nombre del archivo (y tal vez lo modifica), y el segundo lado modifica el archivo sin cambiar el nombre (bajo el nombre anterior).
Tanto Git como Mercurial manejan este caso muy bien en la práctica: Git con detección de cambio de nombre , Mercurial con seguimiento de cambio de nombre .
HTH
fuente
<pre>...</pre>
bloque no está sangrada como debería ser ...--reintegrate
es obsoleto.Yo también he estado buscando un caso en el que, por ejemplo, Subversion no pueda fusionar una rama y Mercurial (y Git, Bazaar, ...) hace lo correcto.
El Libro SVN describe cómo se fusionan incorrectamente los archivos renombrados . ¡Esto se aplica a Subversion 1.5 , 1.6 , 1.7 y 1.8 ! He intentado recrear la situación a continuación:
Según el libro, la fusión debería finalizar limpiamente, pero con datos incorrectos en el archivo renombrado ya que
trunk
se olvida la actualización . En cambio, aparece un conflicto de árbol (esto es con Subversion 1.6.17, la versión más reciente de Debian en el momento de la escritura):No debería haber ningún conflicto en absoluto: la actualización debe fusionarse con el nuevo nombre del archivo. Mientras Subversion falla, Mercurial maneja esto correctamente:
Antes de la fusión, el repositorio se ve así (desde
hg glog
):El resultado de la fusión es:
En otras palabras: Mercurial tomó el cambio de la revisión 1 y lo fusionó con el nuevo nombre de archivo de la revisión 2 (
hello.en.txt
). Por supuesto, el manejo de este caso es esencial para admitir la refactorización y la refactorización es exactamente el tipo de cosas que querrá hacer en una sucursal.fuente
Sin hablar de las ventajas habituales (confirmaciones fuera de línea, proceso de publicación , ...) aquí hay un ejemplo de "fusión" que me gusta:
El escenario principal que sigo viendo es una rama en la que ... se desarrollan dos tareas no relacionadas
(comenzó desde una característica, pero condujo al desarrollo de esta otra característica.
O comenzó desde un parche, pero condujo a la desarrollo de otra característica).
¿Cómo fusionar solo una de las dos características en la rama principal?
¿O cómo aíslas las dos características en sus propias ramas?
Podría intentar generar algún tipo de parches, el problema es que ya no está seguro de las dependencias funcionales que podrían haber existido entre:
Git (y Mercurial también, supongo) proponen la opción rebase --onto para rebase (restablecer la raíz de la rama) parte de una rama:
De la publicación de Jefromi
puede desenredar esta situación en la que tiene parches para la v2, así como una nueva función de wss en:
, permitiéndole:
La otra característica que me gusta (que influye en las fusiones) es la capacidad de aplastar las confirmaciones (en una rama que aún no se ha enviado a otro repositorio) para presentar:
Eso asegura fusiones que son mucho más fáciles, con menos conflictos.
fuente
Recientemente migramos de SVN a GIT, y enfrentamos esta misma incertidumbre. Hubo mucha evidencia anecdótica de que GIT era mejor, pero fue difícil encontrar algún ejemplo.
Sin embargo, puedo decirte que GIT es MUCHO MEJOR en la fusión que SVN. Esto es obviamente anecdótico, pero hay una tabla a seguir.
Estas son algunas de las cosas que encontramos:
Cuando estábamos evaluando GIT, realizamos las siguientes pruebas. Estos muestran a GIT como el ganador cuando se trata de fusionarse, pero no tanto. En la práctica, la diferencia es mucho mayor, pero supongo que no hemos logrado replicar las situaciones que SVN maneja mal.
fuente
Otros han cubierto los aspectos más teóricos de esto. Tal vez pueda prestar una perspectiva más práctica.
Actualmente estoy trabajando para una empresa que usa SVN en un modelo de desarrollo de "rama de características". Es decir:
En general, funciona. SVN se puede usar para un flujo como este, pero no es perfecto. Hay algunos aspectos de SVN que se interponen en el camino y dan forma al comportamiento humano. Eso le da algunos aspectos negativos.
^/trunk
. Esta hojarasca combina registros de información en todo el árbol y, finalmente, rompe el seguimiento de combinación. Comienzan a aparecer falsos conflictos y reina la confusión.svn merge
hace lo que quieres La fusión de sus cambios requiere (se nos dice)--reintegrate
del comando de fusión. Nunca he entendido realmente este interruptor, pero significa que la rama no puede fusionarse nuevamente en el tronco. Esto significa que es una rama muerta y que debe crear una nueva para continuar trabajando. (Ver nota)Lo que suele suceder es que un ingeniero crea una sucursal el día 1. Comienza su trabajo y lo olvida. Algún tiempo después, aparece un jefe y le pregunta si puede liberar su trabajo a la cajuela. El ingeniero ha temido este día porque reintegrarse significa:
... y debido a que el ingeniero hace esto tan poco como puede, no puede recordar el "encantamiento mágico" para hacer cada paso. Cambios y URL incorrectos suceden, y de repente están en un lío y van a buscar al "experto".
Con el tiempo, todo se calma y la gente aprende a lidiar con las deficiencias, pero cada principiante pasa por los mismos problemas. La realidad final (a diferencia de lo que expuse al comienzo) es:
...pero...
Afortunadamente, el equipo es lo suficientemente pequeño como para hacer frente, pero no escalaría. La cosa es que nada de esto es un problema con CVCS, pero más aún porque las fusiones no son tan importantes como en DVCS no son tan resbaladizas. Esa "fusión de fusión" provoca un comportamiento que significa que un modelo de "Rama de características" comienza a descomponerse. Las buenas fusiones deben ser una característica de todos los VCS, no solo DVCS.
De acuerdo con esto , ahora hay un
--record-only
interruptor que podría usarse para resolver el--reintegrate
problema, y aparentemente v1.8 elige cuándo reintegrarse automáticamente, y no causa que la rama esté muerta despuésfuente
Antes de la subversión 1.5 (si no me equivoco), la subversión tenía una desventaja significativa en que no recordaría el historial de fusión.
Veamos el caso descrito por VonC:
Observe las revisiones A y B. Digamos que fusionó los cambios de la revisión A en la rama "wss" a la rama "solo v2" en la revisión B (por cualquier razón), pero continuó usando ambas ramas. Si intentara fusionar las dos ramas nuevamente usando mercurial, solo fusionaría los cambios después de las revisiones A y B. Con la subversión, tendría que fusionar todo, como si no hubiera fusionado antes.
Este es un ejemplo de mi propia experiencia, donde la fusión de B a A llevó varias horas debido al volumen de código: eso habría sido un verdadero dolor que pasar por una vez más , lo que habría sido el caso de pre-1,5 subversión.
Otra diferencia, probablemente más relevante en el comportamiento de fusión de Hginit: Subversion Re-education :
En resumen, la forma en que Mercurial analiza las diferencias es (¿era?) Superior a la de la subversión.
fuente