version control - usados - Mercurial: Ramas con nombre frente a múltiples repositorios
¿qué es un sistema control de versiones centralizado? (6)
Creo que es claramente una decisión pragmática según la situación actual, por ejemplo, el tamaño de una función / rediseño. Creo que las bifurcaciones son realmente buenas para los contribuyentes que aún no se han comprometido a unirse para unirse al equipo de desarrolladores demostrando su aptitud con una sobrecarga técnica descuidada.
Actualmente estamos utilizando subversion en una base de código relativamente grande. Cada versión obtiene su propia rama, y las correcciones se realizan contra el tronco y se migran a las ramas 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 tiempo.
Sin embargo, parece haber dos escuelas en el manejo de dicha estructura de lanzamiento usando Mercurial. O bien cada versión obtiene su propio repositorio y las correcciones se realizan contra la rama de publicación y se envían a la rama principal (y a cualquier otra rama de publicación más nueva) O utilizando ramas con nombre dentro de un único repositorio (o varias copias coincidentes).
En cualquier caso, parece que podría estar usando algo como el trasplante para marcar los cambios para incluirlos en las ramas de publicación.
Te pregunto; ¿Cuáles son los méritos relativos de cada enfoque?
Creo que quieres toda la historia en un repo. Engendrar un repositorio a corto plazo es para experimentos a corto plazo, no para eventos 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 ramas son para siempre Simpatizo con no querer abandonar la historia, pero las ramas 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 repositorio con una rama con nombre por lanzamiento.
Luego, tenga un clon por rama de publicación para construir y probar.
Una nota clave es que incluso si usa múltiples repositorios, debe evitar el uso de transplant
para mover los conjuntos 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 conjuntos de cambios Usted trasplanta y la rama objetivo. 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 dijo @mg 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 repositorios, el repositorio "troncal" (o predeterminado, principal, desarrollo, lo que sea) contiene TODOS los conjuntos de cambios en TODOS los repositorios. Cada repositorio de release / branch es simplemente una rama 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 repositorio principal y el repositorio único en el esquema de sucursal nombrado es simplemente si las ramas son nombradas o no.
Eso debería hacer obvio por qué dije "comenzar con un repositorio". Ese repositorio único es el único lugar en el que tendrá que buscar cualquier conjunto de cambios en cualquier versión . Además, puede etiquetar conjuntos de cambios en las ramas 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 tiempo.
Pero aún necesita mantener un clon por rama / versión que necesite construir y probar. Es trivial, ya que puede hg clone <main repo>#<branch> <branch repo>
, y luego hg pull
en el repositorio de rama solo extraerá nuevos conjuntos de cambios en esa rama (más ancestros conjuntos de cambios en las ramas anteriores que se fusionaron).
Esta configuración se adapta mejor al modelo 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 repositorios de sucursales es puramente para administración de lanzamientos y puede ser completamente automatizado. Los desarrolladores nunca necesitan tirar desde / presionar a los repositorios de sucursales.
Aquí está el ejemplo de @ mg relanzado para esta configuración. Punto de partida:
[a] - [b]
Cree una rama 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 conjunto de cambios real ya que la rama nombrada no existe hasta que se compromete. (Podría hacer una confirmación trivial, como agregar una etiqueta, para asegurarse de que las ramas con nombre se creen correctamente).
La fusión [m1]
es la clave de esta configuración. A diferencia de un repositorio de desarrolladores donde puede haber un número ilimitado de encabezados, NO querrás tener múltiples encabezados en tu repositorio principal (a excepción de la rama de versiones antiguas y muertas, como se mencionó anteriormente). Por lo tanto, siempre que tenga nuevos conjuntos de cambios en las ramas de publicación, debe fusionarlos de nuevo a la rama predeterminada (o una rama 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 rama predeterminada 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 rama predeterminada:
------- [c] - [d] -------
/ /
[a] - [b] ------------------ [m1] - [m2]
/ /
(1.0) - [x] - [y]
Y este es el clon de rama 1.0:
[a] - [b] - (1.0) - [x] - [y]
Ahora es un ejercicio agregar la siguiente rama de publicación. Si es 2.0, definitivamente se ramificará por defecto. Si es 1.1, puede elegir dividir 1.0 o predeterminado. De todos modos, cualquier nuevo conjunto de cambios en 1.0 debería fusionarse primero en la siguiente rama y luego en la predeterminada. 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:
- Repositorio autoritativo único que contiene el conjunto de cambios completo y el historial de versiones.
- Gestión de versiones clara y simplificada.
- Flujo de trabajo claro y simplificado para desarrolladores e integradores.
- Facilite las iteraciones de flujo de trabajo (revisiones de código) y la automatización (fusión vacía automática).
UPDATE hg hace esto : el repositorio principal contiene las ramas predeterminadas y estables, y el repositorio estable es el clon de rama estable. Sin embargo, no usa una rama versionada, ya que las etiquetas de versión a lo largo de la rama 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 ramas están en un único repositorio. Las sucursales con nombre tienen todo a mano en un solo lugar. Los repositorios 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 argumentos 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.
La mayor diferencia es cómo se registran los nombres de las ramas en el historial. Con ramas nombradas, el nombre de la rama está incrustado en cada conjunto de cambios y se convertirá así en una parte inmutable de la historia. Con los clones no habrá un registro permanente de dónde proviene un conjunto de cambios en particular.
Esto significa que los clones son ideales para experimentos rápidos en los que no desea registrar un nombre de rama, y las ramas con nombre son buenas para las ramas de larga duración ("1.x", "2.x" y similares).
Tenga en cuenta también que un único repositorio puede acomodar fácilmente múltiples ramas ligeras en Mercurial. Tales ramas en el repositorio se pueden marcar para que pueda encontrarlas fácilmente de nuevo. Digamos que ha clonado el repositorio 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 repositorio, 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 repositorio. Su copia de trabajo siempre reflejará un solo conjunto de cambios, el denominado conjunto de cambios padre de copia 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 repositorio 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 rama principal y crear un conjunto 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 conjunto de cambios. Por defecto, hg push
simplemente comparará los repositorios 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 rama de características:
% hg update [y]
% hg merge
Eso dejará su gráfico de repositorio 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 rama:
% 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 conjuntos 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 función 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 incluir 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 menos 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 ramas con nombre. Mantenemos una rama llamada ''estable'' además de la rama ''predeterminada'' y hacemos nuestras versiones basadas en la rama ''estable''. Consulte la página de bifurcación estándar en la wiki para obtener una descripción del flujo de trabajo recomendado.
Realmente recomendaría no usar ramas con nombre para las versiones. Para eso son realmente las etiquetas. Las ramas con nombre están destinadas a desvíos de larga duración, como una rama stable
.
Entonces, ¿por qué no usar etiquetas? Un ejemplo básico:
- El desarrollo ocurre en una sola rama
- Cada vez que se crea un lanzamiento, lo etiqueta 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 etiqueta, realice los cambios y confirme
Eso creará una nueva cabecera sin nombre en la rama default
, aka. una rama 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.