Mantener dos versiones de software separadas de la misma base de código en Control de versiones

45

Digamos que estoy escribiendo dos versiones diferentes del mismo software / programa / aplicación / script y las guardo bajo el control de versiones. La primera versión es una versión "básica" gratuita, mientras que la segunda es una versión "premium" de pago que toma la base de código de la versión gratuita y la amplía con algunas características adicionales de valor agregado. Todos los parches, arreglos o funciones nuevos deben encontrar su camino en ambas versiones.

Actualmente estoy considerando usar mastery developsucursales para la base de código principal (versión gratuita) junto con master-premiumy develop-premiumsucursales para la versión paga. Cuando se realiza un cambio en la versión gratuita y se fusiona con la masterrama (después de una prueba exhaustiva, por developsupuesto), se copia a la develop-premiumrama a través del cherry-pickcomando para más pruebas y luego se fusiona master-premium.

¿Es este el mejor flujo de trabajo para manejar esta situación? ¿Hay problemas potenciales, advertencias o dificultades a tener en cuenta? ¿Existe una mejor estrategia de ramificación que la que ya se me ocurrió?

¡Su retroalimentación es muy apreciada!

PD: Esto es para un script PHP almacenado en Git, pero las respuestas deberían aplicarse a cualquier lenguaje o VCS.

Joseph Leedy
fuente

Respuestas:

83

En lugar de tener dos versiones de código con una base común, debe diseñar su aplicación de manera que las características premium se puedan conectar y controlar mediante la configuración en lugar de las diferentes bases de código.

Si tiene miedo de enviar esas características premium (deshabilitadas por la configuración) con la versión básica, aún puede eliminar ese código en un paso final de compilación / empaque y solo tiene dos perfiles de compilación.

Con este diseño, también puede enviar 5 sabores diferentes y ser muy flexible, tal vez incluso permitiendo que terceros contribuyan.

OliverS
fuente
2
Sí, esto es en lo que empecé a pensar anoche antes de acostarme. ¡Gracias!
Joseph Leedy
3
Windows moderno está diseñado de esta manera, todas las versiones tienen el mismo código y tienen funciones desbloqueadas dependiendo de la clave de licencia en uso.
Mooing Duck
39

Recomiendo no utilizar ramas para este propósito. En general, debe considerar las ramas para las cosas que se fusionarán (o podrían) fusionarse nuevamente más tarde (o para las ramas de liberación, donde eventualmente detendrá el desarrollo de una de las ramas). En su caso, nunca fusionará sus versiones "básica" y "premium" juntas, y ambas se mantendrán indefinidamente, por lo que las ramas no son apropiadas.

En cambio, mantenga una versión común del código fuente y use la compilación condicional (por ejemplo, #ifdefen C / C ++, no estoy seguro de cuál es el equivalente para PHP) para incluir o excluir las secciones de código que difieren entre "básico" y "premium".

Parece que PHP podría no tener una función de compilación condicional incorporada, por lo que podría usar el preprocesador C ( cppprobablemente ya lo tenga) para preprocesar su código fuente común y, a partir de eso, producir un "básico" y un "premium" versión sin las directivas de preprocesador. Por supuesto, si elige hacer esto, debe usar makealgo similar para automatizar el proceso de ejecución del preprocesador.

Greg Hewgill
fuente
¡Lo que dices sobre las ramas tiene sentido! ¿Quizás podría crear un repositorio separado que contenga solo el código Premium y usar algún tipo de script de lanzamiento o un submódulo para combinarlo con el código base? Sin embargo, esto podría hacer que TDD sea más difícil ...
Joseph Leedy
14
¡Crear otro repositorio es aún peor que crear ramas! Definitivamente desea elegir una solución que implique la menor duplicación de código versionado.
Greg Hewgill
2
El objetivo del segundo repositorio es alojar solo el código adicional, no otra copia de toda la aplicación.
Joseph Leedy
1
Ah, ya veo, sería más como el modelo de "complemento", donde su código básico tiene la capacidad de cargar y ejecutar complementos (si existen). El código del complemento está separado y proporciona las características premium.
Greg Hewgill
44
@Joseph: el uso de dos repositorios solo es apropiado si la versión de las dos bases de código es casi independiente entre sí. Si ese no es el caso, recomendaría encarecidamente hacer lo que Greg escribió y mantener todo en un repositorio. Lo único que volvería a pensar es el uso del "preprocesador C". Supongo que una pequeña secuencia de comandos escrita en el idioma de su elección (PHP en sí está bien, Perl o Python aún mejor) que hace una copia de su código sin las características premium (algo marcadas) haría el truco.
Doc Brown
8

Estamos utilizando 2 proyectos separados, el Básico y el Premium que depende del proyecto Básico. No use braches, generalmente se usan para funciones.

Silviu Burcea
fuente
Esto me atrae, porque puede usar su script de compilación para automatizar la creación de programas básicos y premium.
neontapir
1
en general, necesita 3 proyectos: parte común, a menudo organizada como una biblioteca, y partes personalizadas para dos versiones diferentes.
Andriy Tylychko
3

Si bien la mayoría de las respuestas actuales están a favor de la compilación condicional en lugar de las ramas, hay un escenario en el que existe un beneficio claro al usar ramas: si usted (ahora o más tarde) decide hacer que el código fuente de la versión básica esté disponible, incluyendo todos los historial de versiones, pero excluyendo todas las características premium, puede hacerlo con el enfoque de ramas pero no con una sola rama y compilación condicional.

Aconsejaría contra la selección de cerezas, y en su lugar fusionar todos los cambios de la versión básica a la versión premium. No debería haber ninguna función o corrección de errores incluida en la versión básica pero que falta en la versión premium. Para que las cosas sean lo menos dolorosas posible, debe asegurarse de que la rama premium modifique los archivos comunes lo menos posible. Por lo tanto, la rama premium debería contener principalmente archivos adicionales y quizás algunas ligeras modificaciones para compilar instrucciones. De esa manera, los cambios de la versión básica se fusionarán automáticamente sin causar conflictos.

La respuesta de Greg sugirió que "considere las ramas para las cosas que se fusionarán (o podrían volver a fusionarse) más tarde". Con el enfoque que acabo de describir este es el caso, excepto que la rama final para todos los envíos será master-premiumno master(que es en realidad master-basic).

Por supuesto, los submódulos también serían una opción. Depende de su proceso de compilación, pero si puede convertir la versión premium en un proyecto que utiliza la versión básica como módulo, estaría bien. Sin embargo, es posible que tenga más dificultades si en algún momento decide elegir las características de la rama premium a la rama básica. Con los submódulos, dicho cambio se representaría como dos confirmaciones distintas, mientras que con las ramas sería una confirmación única para la versión básica, y la próxima combinación en la versión premium sabría que estos cambios ya están incluidos y no tienen para fusionarse de nuevo.

MvG
fuente
0

En "hardware" esto se hace a menudo, son sistemas vendidos para controlar el desorden, lo siento, no recuerdo cómo se llaman.

Una vez que se envía la lavadora de "rango medio", su código no se cambia más que para una corrección de errores muy importante, incluso cuando se cambia el mismo código en la lavadora de "gama baja" que se envía unos meses más tarde.

Los clientes no esperan obtener actualizaciones de una lavadora que ya han traído, tampoco se envía un nuevo modelo cada pocos meses.

La mayoría de nosotros no vivimos en ese mundo, así que haga lo que Greg dice a menos que esté escribiendo software para lavadoras.

Ian
fuente