Combinar correcciones de errores del tronco en ramas viejas

9

Ahora estamos en el proceso de cambiar de svn a git (después de un año dedicado a convencer a la gente, ¡sí!) En mi empresa.

Hasta ahora, esto es para mejor, pero hay una pequeña cosa que tenemos actualmente en nuestro flujo de trabajo que no puedo encontrar un buen equivalente también.

Actualmente, todos nuestros desarrolladores trabajan en master. Una vez cada trimestre, ramificamos master en Xx branch, que más tarde se convertirá en nuestro último lanzamiento. Esto significa que nuestro repositorio svn se ve así:

  • maletero
  • ramas
    • 3.8
    • 4.1
    • 4.2 4.2
    • ...

Realmente no usamos etiquetas.

De vez en cuando, se descubre una corrección de errores urgente.

La forma actual de hacerlo es:

  • Arreglarlo en master
  • SVN fusiona el rango relevante de confirmaciones de nuevo en las ramas relevantes (Tal vez nuestra última versión, tal vez más).

Estamos en la industria espacial, por lo que nuestras sucursales tienen una larga vida y el proceso de actualización del cliente es bastante largo, por lo que hemos trabajado así hasta ahora.

Ahora, ¿cómo sería un buen equivalente en git?

Hasta ahora, he tratado de corregir el error en una rama generada desde master, y luego fusionar esta rama en master y en 4.3 (por ejemplo). La cosa es que la rama de revisión contiene el historial maestro, y todas las confirmaciones entre maestro y 4.3 también se fusionan, lo que no queremos.

Cosas que se me ocurren hasta ahora:

  • He mirado el exitoso método Git Workflow , y su solución es corregir el error en la rama de lanzamiento y fusionarlo de nuevo en lugar de al revés. Esto podría funcionar en nuestro caso, pero sería bastante engorroso porque requeriría que ya conozcamos la rama más antigua en la que queremos corregir el error antes de solucionarlo.
  • Otra solución es arreglarlo en master, y luego elegir los commits (como lo hacemos hoy para la fusión de svn). Lo molesto aquí es que en este caso perdemos el historial de lo que se ha fusionado en el pasado, ya que las selecciones de cereza parecen nuevos compromisos y perdemos la relación.

Entonces, ¿cuál es la "buena" forma de hacerlo? ¿Deberíamos arreglar los commits en la historia, o elegir Cherry y hacer un seguimiento manual de lo que se ha fusionado, o incluso algo más?

Si tiene poca experiencia en producción con git, estoy seguro de que puede haber perdido algo.

jlengrand
fuente

Respuestas:

9

Git Flow supone que solo tiene una única versión compatible, con la masterrama siempre apuntando a la última versión. Como admite varias versiones simultáneamente, no puede copiar ese flujo de trabajo 1: 1. Nvie's Git Flow es un muy buen ejemplo de una estrategia de ramificación, pero debe adaptarla a sus necesidades. Lo más importante, tendrá múltiples ramas de liberación activa.

Cuando identifique un error, deberá realizar algunas pruebas para determinar todas las versiones afectadas. No es suficiente escribir el arreglo primero, luego fusionarlo nuevamente en las ramas de lanzamiento como un hotfix. Por lo general, terminará con un rango continuo de versiones afectadas. Las versiones muy antiguas pueden no contener el error, las versiones más nuevas pueden haber solucionado ese error accidentalmente. Tendrá que verificar el error en cada versión para que pueda verificar que realmente desapareció después de la corrección. Si puede expresar el error como un caso de prueba automatizado, es bastante sencillo encontrar la confirmación problemática a través de git bisect, o ejecutar la prueba para cada versión:

for release in 3.8 4.1 4.2
do
  git checkout $release
  if ./testcase >release-$release.log
  then echo "$release ok"
  else echo "$release AFFECTED"
  fi
done

Ahora, solías escribir la corrección en trunk/ master. Esto es problemático porque la parte con errores puede haber cambiado entre versiones, por lo que un parche generalmente no se aplicará a una versión anterior. En particular, el código masterpuede depender de cualquier característica disponible en master, que podría no haber estado presente en versiones anteriores. Por lo tanto, tiene mucho sentido que un Git commit haga referencia a toda su historia, no solo al conjunto de cambios. Al fusionarse, extraerá toda la historia de la que depende.

Usa cherry-picko rebaseignora este historial y registra una nueva confirmación con el mismo conjunto de cambios, pero con un historial diferente. Como se señaló, esto no funcionará si su base de código ha divergido.

La solución "correcta" es escribir la corrección como una revisión en la versión afectada más antigua. Luego, combina la versión más antigua con la segunda versión más antigua. Por lo general, una versión más nueva contendría todas las confirmaciones de una versión anterior, por lo que está bien. Si las cosas han cambiado, ahora tiene la oportunidad de resolver manualmente el conflicto de fusión. Luego continúa fusionando cada versión en la siguiente versión más joven hasta que haya terminado. Esto mantiene un historial adecuado y evita una gran cantidad de trabajo innecesario, a la vez que solo requiere un esfuerzo que de todos modos tiene que gastarse. En particular, esta fusión incremental te acerca al estado de desarrollo actual en pequeños pasos.

Como un diagrama:

| o normal commit |
| x hotfix        |
| ⇘ merging       |

3.8 --o-----------------x
       \                 ⇘
4.1     o--o--o-----------x'
               \           ⇘
4.2             o--o--o-----x''
                       \     ⇘
develop                 o--o--x'''--o--o
amon
fuente
2
Para completar, digamos que la prueba fue un poco incorrecta y la versión 3.7 tiene el mismo error (por ejemplo, solo ocurre en un caso límite en 3.7, pero ocurre en casos más fáciles de probar en 3.8+), pero solo se descubrió después de La solución se fusionó así. ¿Simplemente elegirías en ese punto?
Izkata
2
@Izkata sí, en ese momento ya no es posible fingir que hay algún tipo de historia sensata, por lo que elegir cerezas es una buena manera de aplicar los cambios a una versión anterior. Sin embargo, esto implica que las ramas de la versión han divergido, y las versiones más nuevas ya no contienen todas las confirmaciones de versiones anteriores. Por lo tanto, deberíamos volver a hacer la cadena de fusión desde el lanzamiento que cambiamos hasta la rama de desarrollo. Sin embargo, durante la primera fusión, podemos descartar los cambios seleccionados ya que ya habíamos aplicado la corrección a la versión más reciente.
amon
Gracias por contestar @amon. Su respuesta es muy completa y va en la dirección que ya estaba mirando, por lo que es bueno tener validación. Asumiremos nuestros propios requisitos de la industria y adaptaremos el enfoque de flujo de git a algo que nos quede mejor. ¡Gracias de nuevo!
jlengrand