Mercurial: Ramas con nombre frente a múltiples repositorys

Actualmente estamos utilizando subversion en una base de código relativamente grande. Cada versión obtiene su propia twig, y ​​las correcciones se realizan contra el tronco y se migran a las twigs de liberación mediante svnmerge.py

Creo que ha llegado el momento de pasar a un mejor control de la fuente, y he estado jugando con Mercurial por un time.

Sin embargo, parece haber dos escuelas en el event handling dicha estructura de lanzamiento usando Mercurial. O bien cada versión obtiene su propio repository y las correcciones se realizan contra la twig de publicación y se envían a la twig principal (y a cualquier otra twig de publicación más nueva) O utilizando twigs con nombre dentro de un único repository (o varias copys coincidentes).

En cualquier caso, parece que podría estar usando algo como el trasplante para marcar los cambios para includelos en las twigs de publicación.

Te pregunto; ¿Cuáles son los méritos relativos de cada enfoque?

La mayor diferencia es cómo se registran los nombres de las twigs en el historial. Con twigs nombradas, el nombre de la twig está embedded en cada set de cambios y se convertirá así en una parte inmutable de la historia. Con los clones no habrá un logging permanente de dónde proviene un set de cambios en particular.

Esto significa que los clones son ideales para experimentos rápidos en los que no desea registrar un nombre de twig, y ​​las twigs con nombre son buenas para las twigs de larga duración ("1.x", "2.x" y similares).

Tenga en count también que un único repository puede acomodar fácilmente múltiples twigs ligeras en Mercurial. Tales twigs en el repository se pueden marcar para que pueda encontrarlas fácilmente de nuevo. Digamos que ha clonado el repository de la compañía cuando se veía así:

 [a] --- [b] 

Cortas y haces [x] y [y] :

 [a] --- [b] --- [x] --- [y] 

Significa que alguien pone [c] y [d] en el repository, de modo que cuando lo hagas obtienes un gráfico de historial como este:

             [x] --- [y]
            /
 [a B C D]

Aquí hay dos cabezas en un solo repository. Su copy de trabajo siempre reflejará un solo set de cambios, el denominado set de cambios padre de copy de trabajo. Verifique esto con:

 % hg parents 

Digamos que informa [y] . Puedes ver las cabezas con

 % hg heads 

y esto informará [y] y [d] . Si desea actualizar su repository a una comprobación limpia de [d] , simplemente realice (sustituya [d] con el número de revisión de [d] ):

 % hg update --clean [d] 

Verá que los hg parents informan [d] . Esto significa que su próxima confirmación tendrá [d] como padre. Por lo tanto, puede corregir un error que haya notado en la twig principal y crear un set de cambios [e] :

             [x] --- [y]
            /
 [a B C D e]

Para presionar changeset [e] solamente, debe hacer

 % hg push -r [e] 

donde [e] es el hash del set de cambios. Por defecto, hg push simplemente comparará los repositorys y verá que faltan [x] , [y] y [e] , pero es posible que aún no desee compartir [x] e [y] .

Si la corrección de error también lo afecta, desea fusionarlo con su twig de características:

 % hg update [y] % hg merge 

Eso dejará su gráfico de repository con el siguiente aspecto:

             [x] --- [y] ----------- [z]
            / /
 [a B C D e]

donde [z] es la fusión entre [y] y [e] . También podría haber optado por tirar la twig:

 % hg strip [x] 

Mi punto principal de esta historia es este: un solo clon puede representar fácilmente varias pistas de desarrollo. Esto siempre ha sido cierto para "hg simple" sin usar ninguna extensión. La extensión de marcadores es de gran ayuda, sin embargo. Le permitirá asignar nombres (marcadores) a sets de cambios. En el caso anterior, querrás un marcador en tu cabeza de desarrollo y otro en la cabeza de subida. Los marcadores se pueden empujar y tirar con Mercurial 1.6 y se han convertido en una function incorporada en Mercurial 1.8.

Si hubiera optado por hacer dos clones, su clon de desarrollo se vería así después de hacer [x] y [y] :

 [a] --- [b] --- [x] --- [y] 

Y tu clon de subida contendrá:

 [a] --- [b] --- [c] --- [d] 

Ahora nota el error y lo arregla. Aquí no es necesario hg update ya que el clon de subida está listo para usar. Usted comete y crea [e] :

 [a] --- [b] --- [c] --- [d] --- [e] 

Para include la corrección de errores en su clonación de desarrollo, acceda allí:

 [a] --- [b] --- [x] --- [y]
            \
             [c] --- [d] --- [e]

y fusionar:

 [a] --- [b] --- [x] --- [y] --- [z]
            \ /
             [c] --- [d] --- [e]

El gráfico puede parecer diferente, pero tiene la misma estructura y el resultado final es el mismo. Usando los clones, debiste hacer un poco less de contabilidad mental.

Las sucursales con nombre no entraron realmente en escena aquí porque son bastante opcionales. Mercurial se desarrolló utilizando dos clones durante años antes de que cambiáramos a utilizar twigs con nombre. Mantenemos una twig llamada 'estable' además de la twig 'pnetworkingeterminada' y hacemos nuestras versiones basadas en la twig 'estable'. Consulte la página de bifurcación estándar en la wiki para get una descripción del flujo de trabajo recomendado.

Creo que quieres toda la historia en un repo. Engendrar un repository a corto ploop es para experimentos a corto ploop, no para events importantes como lanzamientos.

Una de las decepciones de Mercurial es que no parece haber una manera fácil de crear una sucursal efímera, jugar con ella, abandonarla y recolectar la basura. Las twigs son para siempre Simpatizo con no querer abandonar la historia, pero las twigs súper baratas y desechables son una característica que realmente me gustaría ver en hg .

Deberías hacer ambas cosas .

Comience con la respuesta aceptada de @Norman: use un repository con una twig con nombre por lanzamiento.

Luego, tenga un clon por twig de publicación para build y probar.

Una nota key es que incluso si usa múltiples repositorys, debe evitar el uso de transplant para mover los sets de cambios entre ellos porque 1) cambia el hash, y 2) puede presentar errores que son muy difíciles de detectar cuando hay cambios conflictivos entre los sets de cambios Usted trasplanta y la twig objective. En su lugar, quiere hacer la fusión habitual (y sin exclusión previa: siempre inspeccionar visualmente la fusión), lo que dará como resultado lo que @mg dijo al final de su respuesta:

El gráfico puede parecer diferente, pero tiene la misma estructura y el resultado final es el mismo.

Más ampliamente, si usa múltiples repositorys, el repository "troncal" (o pnetworkingeterminado, principal, desarrollo, lo que sea) contiene TODOS los sets de cambios en TODOS los repositorys. Cada repository de release / branch es simplemente una twig en el trunk, todo se fusionó de una forma u otra hasta el trunk, hasta que quiera dejar atrás una versión anterior. Por lo tanto, la única diferencia real entre el repository principal y el repository único en el esquema de sucursal nombrado es simplemente si las twigs son nombradas o no.

Eso debería hacer obvio por qué dije "comenzar con un repository". Ese repository único es el único lugar en el que tendrá que search cualquier set de cambios en cualquier versión . Además, puede labelr sets de cambios en las twigs de publicación para el control de versiones. Es conceptualmente claro y simple, y simplifica el administrador del sistema, ya que es lo único que tiene que estar disponible y ser recuperable todo el time.

Pero aún necesita mantener un clon por twig / versión que necesite build y probar. Es trivial, ya que puede hg clone <main repo>#<branch> <branch repo> , y luego hg pull en el repository de twig solo extraerá nuevos sets de cambios en esa twig (más ancestros sets de cambios en las twigs anteriores que se fusionaron).

Esta configuration se adapta mejor al model de Linux kernel commit del único extractor (no se siente bien actuar como Lord Linus. En nuestra empresa lo llamamos integrador de roles), ya que el repo principal es lo único que los desarrolladores necesitan clonar y el el tirador necesita entrar. El mantenimiento de los repositorys de sucursales es puramente para administración de lanzamientos y puede ser completamente automatizado. Los desarrolladores nunca necesitan tirar desde / presionar a los repositorys de sucursales.


Aquí está el ejemplo de @ mg relanzado para esta configuration. Punto de partida:

 [a] - [b] 

Cree una twig con nombre para una versión de lanzamiento, digamos "1.0", cuando llegue a la versión alfa. Commit correcciones de errores en él:

 [a] - [b] ------------------ [m1] \ / (1.0) - [x] - [y] 

(1.0) no es un set de cambios real ya que la twig nombrada no existe hasta que usted se compromete. (Podría hacer una confirmación trivial, como agregar una label, para asegurarse de que las twigs con nombre se creen correctamente).

La fusión [m1] es la key de esta configuration. A diferencia de un repository de desarrolladores donde puede haber un número ilimitado de encabezados, NO querrás tener múltiples encabezados en tu repository principal (a exception de la twig de versiones antiguas y muertas, como se mencionó anteriormente). Por lo tanto, siempre que tenga nuevos sets de cambios en las twigs de publicación, debe fusionarlos de nuevo a la twig pnetworkingeterminada (o una twig de versión posterior) inmediatamente. Esto garantiza que cualquier corrección de errores en una versión también se incluye en todas las versiones posteriores.

Mientras tanto, el desarrollo en la twig pnetworkingeterminada continúa hacia la próxima versión:

  ------- [c] - [d] / [a] - [b] ------------------ [m1] \ / (1.0) - [x] - [y] 

Y, como de costumbre, debe unir las dos cabezas en la twig pnetworkingeterminada:

  ------- [c] - [d] ------- / \ [a] - [b] ------------------ [m1] - [m2] \ / (1.0) - [x] - [y] 

Y este es el clon de twig 1.0:

 [a] - [b] - (1.0) - [x] - [y] 

Ahora es un ejercicio agregar la siguiente twig de publicación. Si es 2.0, definitivamente se ramificará por defecto. Si es 1.1, puede elegir dividir 1.0 o pnetworkingeterminado. De todos modos, cualquier nuevo set de cambios en 1.0 debería fusionarse primero en la siguiente twig y luego en la pnetworkingeterminada. Esto se puede hacer automáticamente si no hay conflicto, lo que resulta en una mera fusión.


Espero que el ejemplo aclare mis puntos anteriores. En resumen, las ventajas de este enfoque es:

  1. Repositorio autoritativo único que contiene el set de cambios completo y el historial de versiones.
  2. Gestión de versiones clara y simplificada.
  3. Flujo de trabajo claro y simplificado para desarrolladores e integradores.
  4. Facilite las iteraciones de flujo de trabajo (revisiones de código) y la automation (fusión vacía automática).

UPDATE hg hace esto : el repository principal contiene las twigs pnetworkingeterminadas y estables, y el repository estable es el clon de twig estable. Sin embargo, no usa una twig versionada, ya que las tags de versión a lo largo de la twig estable son lo suficientemente buenas para sus propósitos de administración de versiones.

La diferencia más importante, hasta donde yo sé, es algo que ya has dicho: los nombres con twigs están en un único repository. Las sucursales con nombre tienen todo a mano en un solo lugar. Los repositorys separados son más pequeños y fáciles de mover. La razón por la que hay dos escuelas de pensamiento sobre esto es que no hay un ganador claro. Los arguments de cualquiera de los bandos que tengan más sentido para ti probablemente sean los que debes elegir, ya que es probable que su entorno sea más similar al tuyo.

Creo que es claramente una decisión pragmática según la situación actual, por ejemplo, el tamaño de una function / networkingiseño. Creo que los tenedores son muy buenos para los contribuyentes que aún no se han comprometido a join al equipo de desarrolladores demostrando su aptitud con una sobrecarga técnica negligetable.

Realmente recomendaría no usar twigs con nombre para las versiones. Para eso son realmente las tags. Las twigs con nombre están destinadas a desvíos de larga duración, como una twig stable .

Entonces, ¿por qué no usar tags? Un ejemplo básico:

  • El desarrollo ocurre en una sola twig
  • Cada vez que se crea un lanzamiento, lo label como corresponde
  • El desarrollo simplemente continúa desde allí
  • Si tiene algunos errores para corregir (o lo que sea) en una versión determinada, simplemente actualice su label, realice los cambios y confirme

Eso creará una nueva cabecera sin nombre en la twig default , aka. una twig anónima, que está perfectamente bien en hg. En ese momento, puede combinar las correcciones de errores nuevamente en la pista de desarrollo principal. No hay necesidad de sucursales con nombre.