Estrategias para fusionar 1 año de desarrollo en Visual Studio

32

Tengo un cliente que insistió en mantener nuestro nuevo desarrollo separado de las sucursales principales durante todo 2016. Tenían entre 3 y 4 equipos más trabajando en la aplicación en varias capacidades. Se han realizado numerosos cambios importantes (cambio de cómo se realiza la inyección de dependencia, limpieza del código con ReSharper, etc.). Ahora me toca a mí fusionar main en nuestra nueva rama de desarrollo para prepararnos para impulsar nuestros cambios en la cadena.

En mi extracción inicial de fusión, TFS informó ~ 6500 archivos con resolución de conflictos. Algunos de estos serán fáciles, pero algunos serán mucho más difíciles (específicamente algunos de los javascript, los controladores api y los servicios que admiten estos controladores).

¿Hay algún enfoque que pueda tomar que me lo haga más fácil?

Para aclarar, expresé mucha preocupación con este enfoque varias veces en el camino. El cliente era y es consciente de las dificultades con esto. Debido a que eligieron acortar el personal de control de calidad (1 probador para 4 desarrolladores, sin pruebas automatizadas, pruebas de regresión pequeñas), insistieron en que mantengamos nuestra rama aislada de los cambios en la rama principal con el pretexto de que esto reduciría la necesidad de nuestro probador para saber acerca de los cambios que se realizan en otros lugares.

Uno de los problemas más importantes aquí es una actualización de la versión angular y algunos de los otros softwares de terceros; desafortunadamente, no hemos encontrado una buena manera de construir esta solución hasta que todas las piezas vuelvan a estar en su lugar.

usuario258451
fuente
63
No Tiene dos ramas separadas que se desarrollaron activamente durante un año. La fusión va a apestar.
17 de 26
2
¿Cuál es el alcance de los cambios que realizó su equipo? Puede ser más eficiente identificar esos cambios y luego volver a aplicarlos manualmente a la base de código maestra actual.
kdgregory
2
¿Es la totalidad de 2015 o 2016? Si es 2015 son 2 años, lo que significa que será una mierda doble.
David dice que reinstala a Mónica el
1
¿Por qué le importa al cliente si el trabajo que está haciendo para ellos está en una rama separada en su sistema de control de versiones?
Ixrec
17
Hagas lo que hagas, asegúrate de que estás facturando por hora.
Sean McSomething

Respuestas:

37

Hubiera sido una manera simple de mantener su nuevo desarrollo separado de la rama principal sin llevarlo a esta desafortunada situación: cualquier cambio desde la troncal debería haberse fusionado en su rama de desarrollo diariamente . (¿Fue su cliente realmente tan miope que no pudo anticipar que su sucursal necesita volver a estar en la línea principal algún día?)

De todos modos, el mejor enfoque es en mi humilde opinión tratar de rehacer lo que debería haber sucedido de primera mano:

  • Identifique la semántica de los cambios en la línea principal para el día 1 después de la creación de la rama. Aplíquelos a su base de código actual tan bien como pueda. Si se trataba de un "cambio local", debería ser simple, si se tratara de una "refactorización transversal" como cambiar el nombre de una clase ampliamente utilizada, aplíquela de manera semánticamente equivalente a su base de código actual. Esperemos que durante ese año no se hayan realizado cambios transversales contradictorios en la base del código en "su" rama, de lo contrario, esto puede convertirse en un verdadero desafío para la mente
  • probar el resultado (¿mencioné que necesita un buen conjunto de pruebas para esta tarea)? Repara todos los errores revelados por la prueba
  • ahora repita este proceso para los cambios en la línea principal para el día 2, luego el día 3, y así sucesivamente.

Esto podría funcionar cuando los equipos obedecían estrictamente a las reglas clásicas de control de versiones ("solo confirman estados compilables, probados" y "check in temprano y frecuente").

Después de 365 repeticiones (o 250, si tiene suerte y puede agrupar el trabajo para los cambios de fin de semana), estará casi terminado (casi, porque necesita agregar el número de cambios que sucederán en la línea principal durante el período de integración) ) El paso final será fusionar la rama de desarrollo actualizada nuevamente en el tronco (para que no pierda el historial del tronco). Esto debería ser fácil, porque técnicamente debería ser solo un reemplazo de los archivos afectados.

Y sí, lo digo en serio, probablemente no hay un atajo para esto. Podría resultar que las "porciones diarias" a veces sean demasiado pequeñas, pero no esperaría esto, supongo que es más probable que las porciones diarias resulten ser demasiado grandes. Espero que su cliente le pague realmente bien por esto, y que esto sea tan costoso para él que aprenderá de su fracaso.

Debo agregar que puedes probar esto también con lados cambiados, reintegrando los cambios desde tu rama en pequeñas porciones a la línea principal. Esto podría ser más simple cuando en su rama de desarrollo hubo muchos menos cambios que en la troncal, o la mayoría de los cambios ocurrieron en nuevos archivos fuente que actualmente no son parte de la troncal. Uno puede ver esto como "portar" una característica de un producto A (la rama de desarrollo) a un producto B algo diferente (estado actual de la troncal). Pero si la mayoría de las refactorizaciones transversales se realizaron en la línea principal y afectan su nuevo código (las colisiones de fusión 6500 parecen ser una evidencia de esto), podría ser más fácil de la forma en que lo describí primero.

Doc Brown
fuente
9
Si continúa desarrollando en el tronco durante la reintegración, le sugiero que ramifique la punta del tronco primero y desarrolle a partir de eso. De lo contrario, está fusionando efectivamente el pasado y el futuro simultáneamente. Pero difiero a Doc Brown sobre cualquier discontinuidad espacio-tiempo, naturalmente.
radarbob
1
@radarbob: lo que sugieres solo tiene sentido si el OP se integra de dev a trunk, pero no cuando decide fusionarse de trunk a dev, como lo describí primero. Si el OP transfiere los cambios de la troncal a su rama de desarrollo día a día (comenzando con los cambios 365 días en el pasado), no importará si el desarrollo en la troncal continúa. Solo tendrá que continuar con esta táctica hasta llegar al presente (se supone que puede integrar y probar los cambios de esos 3-4 equipos en un día en menos de un día).
Doc Brown
Cita: "Debo agregar que puedes probar esto también con lados cambiados, reintegrando los cambios de tu rama en paquetes diarios a la línea principal " . Mi sentido de la araña está quemando un fusible. Percibo una cascada potencial de "distorsión de resonancia armónica" con integraciones de cambio conflictivas.
radarbob
Este es un buen consejo. Ver edición para abordar un par de cosas aquí.
user258451
1
@ user258451: ¿entonces tenía diferentes equipos de control de calidad para la troncal y la nueva sucursal de desarrollo que no querían hablar entre ellos? Gran Scott: - ((
Doc Brown
14

En esa etapa de fusión, diría que la fusión automática solo puede complicar demasiado el proceso. He tenido problemas similares con sucursales que se han separado durante más de un año y el método más efectivo que tengo es hacer lo siguiente:

  • Tome una copia del estado original sin fusionar
  • Diferencia entre lo no combinado y lo último
  • Descomponer cualquier elemento común
    • Por ejemplo, realice todos los cambios de nombre de función, luego los cambios de parámetros, etc.
    • Ignore el espacio en blanco en diff si los estándares han cambiado, de lo contrario perderá mucho tiempo contando espacios
  • Céntrese primero en la funcionalidad principal

Eventualmente, las advertencias del compilador y los diffs serán sus mejores amigos, siga usando el diff no combinado para ver exactamente qué era diferente y simplemente continúe. Puede haber varias herramientas que podría usar para ayudar, pero eso dependerá de usted para determinar cuál es la mejor.

La clave es seguir adelante.

Editar:

Una advertencia: este enfoque significará que el historial de control de versiones se 'corrompería', ya que perdería la evidencia de la fusión de rama a rama, así como el historial de la rama no fusionada.

Gracias a los comentarios de 'Jack Aidley' y '17 de 26 '

Erdrik Ironrose
fuente
1
El principal problema con este enfoque es que destruirá el registro de los cambios que quedan en el sistema de control de versiones.
Jack Aidley
Esencialmente, al hacer todos los mismos cambios por segunda vez durante la fusión, aún tendría un registro de los cambios, solo estaría en el orden en que se realizó la fusión en lugar del orden en que se hicieron durante el desarrollo. No es ideal, pero mejor que nada. Además, todavía tendría el estado original no fusionado, si eso se mantuviera en el control de versiones.
Erdrik Ironrose
Tendría un registro de los cambios, pero no tendría evidencia histórica de que los cambios se fusionaron de rama en rama. Esto sería un gran problema en TFS, que le ofrece solo los conjuntos de cambios no fusionados para elegir cuando se fusiona de rama en rama.
17 de 26
@ 17of26 Si bien estoy de acuerdo en que puede restaurar algunos registros de cambios, 17 de 26 es correcto que este registro no será completo o exacto. Puede ser que este enfoque sea lo suficientemente fácil como para hacer que esta pérdida de registro sea un compromiso aceptable dada la mala situación en la que se encuentran ahora. Sin embargo, creo que es un inconveniente importante reconocer independientemente de lo que decidan.
Jack Aidley
1
@Jack Aidley Definitivamente estoy de acuerdo en que es un problema, así que agregué un poco a mi respuesta para reflexionar. Espero que esté bien?
Erdrik Ironrose
8

Hace unos años teníamos un cliente con los mismos requisitos de mantener las sucursales separadas. Entonces lo hicimos.

Nunca fusionamos su rama de nuevo. Tenían allí su propia versión única. Les cobramos extra por los cambios, ya que esencialmente teníamos dos troncos principales en lugar de 1 tronco principal y ramas.

Intentamos fusionarnos nuevamente con el tronco, pero después de 2 semanas decidimos abandonar ese esfuerzo, ya que estaba quemando horas sin beneficios tangibles.

Entonces, no lo fusiones de nuevo. En el futuro, combine las correcciones críticas para esa sucursal del cliente según sea necesario y cualquier mejora sería una de las cargas específicamente cargadas para ese cliente.

Jon Raynor
fuente
Esta estrategia solo es factible si las diferentes líneas de desarrollo se dirigen a diferentes clientes. O bien, si los casos de uso en los que está involucrado el producto permiten utilizar las dos líneas de productos diferentes en paralelo, de manera no integrada. Según tengo entendido, el OP describe una situación en la que la nueva línea de desarrollo se dirige al mismo cliente que el que está usando el enlace troncal, y no está claro si el uso paralelo de dos líneas de productos podría tener algún sentido para su caso.
Doc Brown
1

No va a ser divertido, pero lo doloroso que sea dependerá de la naturaleza de los cambios y de lo aislados que estén.

Le sugiero que intente converger las ramas refactorizando tanto como sea posible antes de hacer una fusión real.

La herramienta de combinación es un poco tonta porque solo analiza las diferencias textuales y no entiende el código de ninguna manera. Si la rama principal ha cambiado el nombre de una clase utilizada en toda la aplicación, y la rama característica usa el nombre antiguo en algún código nuevo, entonces la herramienta de fusión no comprenderá que el nombre de la clase también debe cambiarse en el nuevo código. Pero si realiza una refactorización en la rama B para cambiar el nombre de la clase como en la rama A, funcionará tanto en el código antiguo como en el nuevo y la fusión se realizará sin problemas.

En segundo lugar, debe inspeccionar qué tan localizados están los cambios en la rama de desarrollo. Si los cambios en la rama de características se localizan en algunas áreas, no tiene que converger el código no afectado, solo puede copiar y sobrescribir desde la rama principal.

En las áreas de código donde ha habido cambios no triviales en ambas ramas, debe inspeccionar cuidadosamente el código y decidir cómo reescribirlo.

JacquesB
fuente