Estrategia de ramificación de Git para código inédito de larga duración

15

En nuestro equipo, además de las unidades de trabajo individuales (Historias), tenemos temas de trabajo de mayor duración (Epics). Múltiples historias hacen una epopeya.

Tradicionalmente, hemos tenido ramas de características para cada historia, y las fusionamos directamente para dominarlas cuando pasan el control de calidad. Sin embargo, nos gustaría comenzar a retrasar el lanzamiento de historias completadas en una Epic hasta que la Epic se considere "característica completa". Solo lanzaríamos estas características a producción cuando se cierre todo el Epic. Además, tenemos un servidor de compilación nocturno: nos gustaría que todas las historias cerradas (incluidas las que forman parte de Epics incompletas) se implementen en este servidor nocturno automáticamente.

¿Hay alguna sugerencia sobre cómo administrar nuestro repositorio para lograr esto? He considerado introducir "ramas épicas", donde fusionaríamos historias cerradas con la rama épica relacionada en lugar de dirigirlas directamente al maestro, pero mis preocupaciones son:

  • Me preocupan los conflictos de fusión que pueden surgir si las ramas épicas se mantienen abiertas durante mucho tiempo.
  • Las construcciones nocturnas requerirían fusionar todas las ramas épicas en una rama de "construcción nocturna". Nuevamente, podrían surgir conflictos de fusión, y esto debe hacerse automáticamente
Sitati
fuente

Respuestas:

23

Sugerencia simple: no hagas eso.

Las ramas git no son para tenedores de código de larga duración, como se discutió aquí y https://blog.newrelic.com/2012/11/14/long-running-branches-considered-harmful/ . Las ramas se tratan mejor como cosas transitorias que un desarrollador individual utiliza para organizar las confirmaciones a nivel diario. Entonces, si tienen un nombre que corresponde a algo que a un gerente de proyecto (y mucho menos al usuario final) podría importarle, usted está haciendo algo mal.

La práctica recomendada es utilizar la integración continua con alternar características o ramificación por abstracción para garantizar que:

  • todo el código está integrado en todo momento (al menos todos los días, preferiblemente con más frecuencia)
  • lo que se implementa está bajo control explícito.
soru
fuente
1
¡Sospeché que esta podría ser una respuesta popular! Mi principal preocupación con esto es la sobrecarga de mantener siempre tanto la implementación 'en vivo' como la 'siguiente', y también requiere que el desarrollador que trabaja en una función sepa por adelantado para generar cambios como nuevas funciones paralelas en lugar de actualizar (/ reemplazar) funcionalidad existente. Supongo que requiere un cambio de mentalidad más grande en el equipo.
Sitati
Está bien usar ramas para desarrollar código, simplemente nunca las use para almacenar código. Entonces, si no está seguro de si una tarea es una reparación de 30 minutos o un retrabajo de 2 semanas, comience en una rama. Tan pronto como lo sepa, fusione o refactorice a una abstracción / alternar y luego fusione.
soru
@Sitati: Acabo de fusionar un código que estaba en una rama de características durante los últimos cuatro meses. Mientras tanto devel, hemos cambiado a CMake desde Autotools, hemos introducido Travis CI, refactorizado el código. Al final, fue más fácil entender la nueva característica y aplicarla manualmente develque tratar de fusionarla. También tuvimos nuevos estudiantes de maestría que desarrollaron una nueva característica en una rama que se ramificaron cuando comenzaron su tesis. Después de un año, lo empujaron y no hubo esfuerzo para fusionarlo, por lo que fue más difícil fusionarlo día tras día.
Martin Ueding
2
La publicación del blog vinculada ahora tiene 5 años. Odio los cambios de funciones. ¿Qué hay de malo en ramificarse a largo plazo, fusionarse regularmente en la rama de características desde main y agregar una integración continua a la rama de características a largo plazo?
Jason Kelley
CI es el nombre de un proceso, no una herramienta. Si tiene más de una rama de características, normalmente no se integrarán continuamente entre sí. Lo que significa encontrar problemas más tarde que antes.
soru
1

Creo que este es un problema bastante común y se reduce a elegir qué características incluir en una versión después de que las características se hayan codificado en lugar de antes.

p.ej.

Tengo características A, B y C para v2 de mi producto. B y C están relacionados, no quiero lanzar B a menos que C también esté terminado.

Tengo tres desarrolladores, todos trabajando al mismo tiempo en las funciones.

Tengo un set en piedra fecha de lanzamiento D

B está terminado y fusionado, A está terminado y fusionado. C está retrasado ... ¿qué debo hacer?

No creo que haya una solución técnica a este problema. Desea lanzar una versión no probada del producto con solo la función A incluida. A menos que combine y pruebe todas las combinaciones posibles de características, esto siempre será una posibilidad.

La solución es más humana. Has perdido tu fecha de lanzamiento y debes retrasarla.

Ewan
fuente
1

Este es un problema complicado pero que muchas personas enfrentan. Prefiero usar la configuración de Gitflow como punto de partida.

Desarrollo -> Nuevas cosas que se están trabajando en
Master -> Cosas terminadas que necesitan pruebas Producción -> Cosas que se han publicado en producción.

En las características menores (más cortas), creo una rama desde el desarrollo, hago el trabajo allí y luego fusiono la rama de nuevo al desarrollo.

En las características principales (a largo plazo) creo una rama desde el desarrollo, creo ramas más pequeñas a partir de esa rama, luego me fusiono con la primera rama. Una vez que se completa la característica principal, vuelve a la rama de desarrollo.

A intervalos regulares (depende del proyecto) Fundo el desarrollo nuevamente en el maestro y comienza un ciclo de prueba. Si surgen soluciones en las pruebas, se realizan en la rama maestra (la sub rama se fusiona). Y el desarrollo puede continuar en la rama maestra durante las pruebas.

En cualquier momento, master debería fusionarse con el desarrollo, y el desarrollo debería fusionarse con cualquiera de sus sub ramas a largo plazo.

master siempre (en teoría) debería estar listo para la producción. El desarrollo siempre debe estar (en teoría) listo para la producción. La única razón por la que hay una diferencia es que proporciona un conjunto sólido de características para que los evaluadores prueben.

Cuando está listo, una confirmación en el maestro que se prueba se fusiona en la producción y el despliegue en la producción ocurre desde esa rama. Los HOTFIX que deben realizarse en caso de emergencia pueden tener lugar en la rama de Producción sin tener que fusionarse en el maestro (que puede tener muchos cambios no probados).

Mi árbol normal se parece a

 LongTerm -> Development -> Master -> Production    
 LongTerm <- Development      |            |  
     |       Development -> Master         |  
 LongTerm <- Development -> Master         |  
             Development <- Master         |  
                            Master -> Production  

Mi regla general es que ningún cambio individual debería llevar más de unas pocas horas. Si lo hace, entonces debe hacerse en cambios más pequeños. Si se trata de una función enorme (como una reescritura de la interfaz de usuario), se aplica a largo plazo para que el desarrollo normal pueda continuar al mismo tiempo. Las sucursales a largo plazo son normalmente solo sucursales locales, mientras que Desarrollo, Maestro y Producción son sucursales remotas. Cualquier sucursal secundaria también es local. Esto mantiene el repositorio limpio para otros, sin perder la utilidad de git en un conjunto de características a largo plazo.

Sin embargo, me gustaría señalar que la existencia de una rama a largo plazo es algo raro. Normalmente, todo mi trabajo está en desarrollo. Solo cuando tengo una función (conjunto) que va a tomar tanto tiempo que necesito poder trabajar también en cosas de desarrollo normales, uso la rama LongTerm. Si es solo un conjunto de cambios que deberían estar juntos, entonces no me fusiono para dominar hasta que todo haya terminado.

coteyr
fuente
"En las características principales (a largo plazo) creo una rama desde el desarrollo" - ¿no debería crear nuevas ramas de características (desarrollo) desde la rama Producción? Ver como la rama de producción es un código listo para el lanzamiento.
robotron
No, la producción ya se lanzó, el maestro está por delante de la producción y el desarrollo está por delante del maestro. Una nueva característica como agregar impuestos a los totales de pedidos no tiene sentido si no está trabajando en un código que ya tiene pedidos.
coteyr
Pero si se ramifica desde dev y luego se fusiona, ¿esa rama (y, en consecuencia, master y Production más adelante) no incorporará todos los cambios de desarrollo realizados por otros hasta el punto de ramificarse? Es posible que algunos de esos cambios no cuenten con la aprobación del control de calidad. Quizás estaban hablando de diferentes enfoques para la gestión de lanzamientos.
robotron
Sí lo hará, ese es el punto. Pruebas de control de calidad en un SHA específico en master, pero no puede detener a los desarrolladores por eso.
coteyr
"Pruebas de control de calidad en un SHA específico en maestro" -> ¿QA prueba cada nueva característica de forma independiente? Permítame correr con usted en un escenario típico que mi equipo enfrenta: digamos que tiene 2 proyectos de larga ejecución en la misma base de código: el Proyecto A está en QA durante el último mes y será QA'd por otro mes. El Proyecto B estuvo en desarrollo durante los últimos 6 meses y ahora está listo para el control de calidad. El Proyecto A se fusionó en maestro y definitivamente no está listo para la producción debido a numerosos errores sutiles en las reglas de negocios. ¿Cómo manejamos el Proyecto B? A y B deben probarse juntos para verificar las interacciones (B no causará conflictos durante la fusión).
robotron