Actualmente, nuestra empresa está utilizando un modelo de ramificación simple de troncal / lanzamiento / revisión y desea recibir asesoramiento sobre qué modelos de ramificación funcionan mejor para su empresa o proceso de desarrollo.
Flujos de trabajo / modelos de ramificación
A continuación se encuentran las tres descripciones principales de esto que he visto, pero se contradicen parcialmente entre sí o no van lo suficientemente lejos como para resolver los problemas posteriores que hemos encontrado (como se describe a continuación). Por lo tanto, nuestro equipo hasta el momento utiliza soluciones no tan buenas. ¿Estás haciendo algo mejor?
Fusión vs rebase (historia enredada vs secuencial)
¿Debería uno
pull --rebase
o esperar con la fusión a la línea principal hasta que su tarea haya finalizado? Personalmente, me inclino por la fusión, ya que esto conserva una ilustración visual de en qué base se inició y finalizó una tarea, e incluso prefieromerge --no-ff
para este propósito. Sin embargo, tiene otros inconvenientes. Además, muchos no se han dado cuenta de la propiedad útil de la fusión: que no es conmutativa (fusionar una rama de tema en maestro no significa fusionar maestro en la rama de tema).Estoy buscando un flujo de trabajo natural.
Algunas veces los errores ocurren porque nuestros procedimientos no capturan una situación específica con reglas simples. Por ejemplo, una solución necesaria para versiones anteriores debería, por supuesto, basarse lo suficientemente corriente abajo como para ser posible fusionarla en todas las ramas necesarias (¿es lo suficientemente claro el uso de estos términos?). Sin embargo, sucede que una solución llega al maestro antes de que el desarrollador se dé cuenta de que debería haberse colocado más abajo, y si eso ya se ha empujado (aún peor, fusionado o algo basado en él), la opción restante es la selección de cereza, con Sus peligros asociados. ¿Qué reglas simples como esas usas?También en esto se incluye la incomodidad de una rama temática excluyendo necesariamente otras ramas temáticas (suponiendo que se ramifiquen a partir de una línea de base común). Los desarrolladores no quieren terminar una característica para comenzar otra sintiendo que el código que acaban de escribir ya no existe.
¿Cómo evitar crear conflictos de fusión (debido a la selección de cereza)?
Lo que parece una forma segura de crear un conflicto de fusión es elegir entre ramas, ¿nunca se pueden volver a fusionar? ¿Aplicar la misma confirmación en revertir (¿cómo hacer esto?) En cualquier rama posiblemente resolvería esta situación? Esta es una razón por la que no me atrevo a impulsar un flujo de trabajo basado en gran medida en la fusión.
¿Cómo descomponerse en ramas tópicas?
Nos damos cuenta de que sería increíble reunir una integración completa a partir de ramas temáticas, pero a menudo el trabajo de nuestros desarrolladores no está claramente definido (a veces tan simple como "hurgar") y si algún código ya ha entrado en un tema "misceláneo", no se puede sacar de allí nuevamente, de acuerdo con la pregunta anterior? ¿Cómo trabaja con la definición / aprobación / graduación / liberación de sus ramas temáticas?
Por supuesto, los procedimientos adecuados, como la revisión del código y la graduación, serían encantadores.
Pero simplemente no podemos mantener las cosas lo suficientemente desenredadas para manejar esto, ¿alguna sugerencia? ramas de integración, ilustraciones?
A continuación se muestra una lista de preguntas relacionadas:
- ¿Cuáles son algunas buenas estrategias para permitir que las aplicaciones implementadas sean reparables?
- Descripción del flujo de trabajo para el uso de Git para el desarrollo interno
- Flujo de trabajo de Git para el desarrollo corporativo del kernel de Linux
- ¿Cómo mantiene el código de desarrollo y el código de producción? (¡gracias por este PDF!)
- gestión de lanzamientos de git
- Flujo de trabajo de Git Cherry-pick vs Merge
- Cómo seleccionar múltiples confirmaciones
- ¿Cómo fusionar archivos selectivos con git-merge?
- Cómo elegir una variedad de confirmaciones y fusionarse en otra rama
- Flujo de trabajo de ReinH Git
- flujo de trabajo de git para realizar modificaciones que nunca volverá a empujar al origen
- Cherry-pick una fusión
- ¿Flujo de trabajo de Git adecuado para SO combinado y código privado?
- Proyecto de mantenimiento con Git
- ¿Por qué no puede Git fusionar cambios de archivos con un padre / maestro modificado?
- Buenas prácticas de ramificación / rebase de Git
- ¿Cuándo "git pull --rebase" me meterá en problemas?
- ¿Cómo se usa DVCS en equipos grandes?
También revise lo que Plastic SCM escribe sobre el desarrollo impulsado por tareas , y si Plastic no es su elección, estudie el modelo de ramificación de nvie y sus scripts de soporte .
Respuestas:
La característica más problemática que los nuevos desarrolladores de DVCS deben tener en cuenta es sobre el proceso de publicación :
A partir de eso, puede respetar algunas reglas para facilitar sus preguntas:
Ahora:
Flujos de trabajo / modelos de ramificación :
cada flujo de trabajo está ahí para soportar un proceso de administración de versiones , y eso se adapta a cada proyecto.
Lo que puedo agregar al flujo de trabajo que menciona es: cada desarrollador no debe crear una rama de características, solo una rama de "desarrollo actual", porque la verdad es que el desarrollador a menudo no sabe qué producirá exactamente su rama: una característica, varias (porque terminó siendo una característica demasiado compleja), ninguna (porque no estaba lista a tiempo para el lanzamiento), otra característica (porque la original se había "transformado"), ...
Solo un "integrador" debe establecer ramas de funciones oficiales en un repositorio "central", que luego los desarrolladores pueden buscar para volver a crear / fusionar la parte de su trabajo que se ajuste a esa función.
Fusión vs rebase (historia enredada vs secuencial) :
Me gusta mi respuesta que mencionas (" Descripción del flujo de trabajo para el uso de git para el desarrollo interno ")
Estoy buscando un flujo de trabajo natural :
para los arreglos, puede ayudar asociar cada arreglo con un ticket de un seguimiento de errores, lo que ayuda al desarrollador a recordar dónde (es decir, en qué rama, es decir, una rama dedicada "para arreglos") él / ella debe cometer tales modificaciones.
Luego, los ganchos pueden ayudar a proteger un repositorio central contra los empujes de correcciones de errores no validadas o de ramas desde las cuales no se debe empujar. (no hay una solución específica aquí, todo esto debe adaptarse a su entorno)
¿Cómo evitar crear conflictos de fusión (debido a la selección de cereza)?
Según lo declarado por Jakub Narębski en su respuesta , la recolección de cerezas debe reservarse para situaciones raras donde se requiere.
Si su configuración implica una gran selección de cerezas (es decir, "no es raro"), entonces algo está apagado.
git revert
debería ocuparse de eso, pero eso no es lo ideal.Mientras una rama aún no haya sido empujada a todas partes, un desarrollador debe reorganizar su historial de confirmaciones (una vez que finalmente vea que el desarrollo toma una forma más definitiva y estable) en:
¿Procedimientos adecuados como revisión de código y graduación?
El repositorio de ramas de integración (en una integración dedicada) puede ayudar al desarrollador a:
fuente
rebase --interactive --autosquash
que moverá automáticamente todas las confirmaciones con el mismo comienzo de otro mensaje de confirmación. Si esas confirmaciones usan un número de ticket (por ejemplo), incluso si esas correcciones relacionadas con ese ticket no se hicieron secuencialmente en ese momento, el autoquash permite un reordenamiento rápido de esas confirmaciones.Creo, y podría estar equivocado, que una de las cosas que más se malinterpreta sobre git es su naturaleza distribuida. Esto hace que sea muy diferente decir subversión en las formas en que puede trabajar, aunque puede imitar el comportamiento SVN si lo desea. El problema es que cualquier flujo de trabajo servirá, lo cual es excelente pero también engañoso.
Si entiendo bien el desarrollo del kernel (me centraré en eso), todos tienen su propio repositorio git para desarrollar el kernel. Hay un repositorio, linux-2.6.git, cuidado por Torvalds, que actúa como repositorio de lanzamiento. Las personas clonan desde aquí si desean comenzar a desarrollar una característica contra la rama de "lanzamiento".
Otros repositorios hacen algún desarrollo. La idea es clonar desde linux-2.6, ramificarse tantas veces como desee hasta el punto en que tenga una función "nueva" que funcione. Luego, cuando esté listo, puede ponerlo a disposición de alguien considerado confiable, que extraerá esta rama de su repositorio en la suya y la fusionará en la corriente principal. En el kernel de Linux, esto sucede en varios niveles (lugartenientes de confianza) hasta que alcanza linux-2.6.git, en cuyo punto se convierte en "el kernel".
Ahora aquí es donde se vuelve confuso. Los nombres de las ramas no necesitan ser consistentes en todos los repositorios. Entonces puedo
git pull origin master:vanilla-code
y obtener una rama delorigin
maestro de 's en una rama en mi repositorio llamadavanilla-code
. Siempre que sepa lo que está sucediendo, realmente no importa: se distribuye en el sentido de que todos los repositorios son iguales entre sí y no solo se comparten en varias computadoras como SVN.Entonces, con todo esto en mente:
head
. Las versiones pueden ser etiquetas o ramas y las revisiones son probablemente ramas en sí mismas. De hecho, probablemente haría lanzamientos como ramas para que puedas seguir parchándolos.origin
debe, en su repositorio, probablemente haría otra rama y combinar la últimamaster
enyourbranch
para que otra persona puede tirar de sus cambios con el menor esfuerzo posible. Muy raramente hay una necesidad de rebase verdaderamente, en mi experiencia.git add .
y luegogit commit
.Espero que eso ayude. Me doy cuenta de que VonC acaba de publicar una explicación muy similar ... ¡No puedo escribir lo suficientemente rápido!
Edite algunas ideas adicionales sobre cómo usar git en un entorno comercial, ya que esto parece relevante para el OP de los comentarios:
product.git
, es accesible por varios programadores senior / técnicos responsables de cuidar el producto en sí. Son análogos al papel de los mantenedores en OSS.¿Así que lo que sucede? Bueno, todo el mundo saca al comienzo de cada día de la fuente "aguas arriba", es decir, el repositorio de lanzamiento (que probablemente también contendrá el material más reciente del desarrollo de los días anteriores). Todos hacen esto, directamente. Esto irá en una rama en su repositorio, probablemente llamado "maestro" o tal vez si usted me llama "último". El programador entonces hará algo de trabajo. Este trabajo puede ser algo de lo que no están seguros, por lo que hacen una rama, hacen el trabajo. Si no funciona, pueden eliminar la rama y volver. Si es así, tendrán que fusionarse con la rama principal en la que están trabajando actualmente. Diremos que este es un programador de UI trabajando,
latest-ui
así que logit checkout latest-ui
siguegit merge abc-ui-mywhizzynewfeature
. Luego le dice a su líder técnico (el líder de la interfaz de usuario) oye, he completado esa tarea, retíreme. Así lo hace el líder de la interfaz de usuariogit pull user-repo lastest-ui:lastest-ui-suchafeature-abc
. El líder de la interfaz de usuario luego lo mira en esa rama y dice, en realidad, eso es muy bueno, lo fusionaréui-latest
. Luego podría decirle a todos los que están debajo de él que tomen de él en susui-latest
ramas o cualquier nombre que les hayan dado, y así los desarrolladores exploran la característica. Si el equipo está contento, el líder de la interfaz de usuario puede pedirle al líder de prueba que se retire de él y combine los cambios. Esto se propaga a todo el mundo (después del cambio) que lo prueba y envía informes de errores, etc. Finalmente, si la función pasa las pruebas, etc., uno de los principales líderes técnicos podría fusionarlo con la copia de trabajo actual del programa, en ese momento Todos los cambios se propagan de nuevo hacia abajo. Y así.No es una forma de trabajo "tradicional" y está diseñada para ser "dirigida por pares" en lugar de "jerárquica" como SVN / CVS. En esencia, todos tienen acceso de compromiso, pero solo localmente. Es el acceso al repositorio y el repositorio que designe como repositorio de lanzamiento lo que le permite usar la jerarquía.
fuente
Un modelo que he usado con buenos resultados es el siguiente:
Un repositorio "bendecido" que todos empujan y sacan, básicamente, una topología cliente-servidor.
No hay una rama maestra, por lo que ningún desarrollador puede insertar ningún código en la "línea principal".
Todos los desarrollos ocurren en ramas temáticas. Colocamos nombres de espacios de nombres para detectar fácilmente quién es responsable de ello: jn / newFeature o jn / issue-1234
También hay un mapeo casi 1 a 1 entre ramas y tarjetas kanban / scrum en la pizarra.
Para liberar una rama, se empuja al repositorio bendecido y la tarjeta kanban se mueve a lista para su revisión.
Luego, si la sucursal es aceptada por la revisión, es un candidato para una liberación.
Un lanzamiento ocurre cuando un conjunto de ramas aceptadas se fusionan y se etiquetan con un número de versión.
Al colocar la nueva etiqueta en el repositorio bendecido, existe una nueva base posible para nuevas funciones.
Para evitar conflictos de fusión, se solicita a los desarrolladores que actualicen (fusionen) sus ramas inéditas a la última etiqueta de lanzamiento.
fuente
Personalmente, trato de mantener solo el código listo para el lanzamiento en la rama maestra.
Cuando trabajo en una nueva función o corrección de errores, lo hago en una rama. También realizo pruebas unitarias en la sucursal. Si todo funciona bien, solo entonces fusiono / rebaso en master.
Intento usar las convenciones de denominación de ramas comunes también, como:
fuente