Trabajar en una sucursal con dependencia de otra sucursal que se está revisando

65

¿Cómo ayuda git a lidiar con el siguiente escenario?

Tengo una tarea dividida en 2 partes: tarea de fondo y tarea de interfaz. Realizo una solicitud de extracción para fusionar los cambios de back-end y espero a que se fusione (y responda a los comentarios). Mientras espero, realmente no puedo trabajar en los cambios frontend porque depende de los cambios de back-end y aún no están disponibles en la rama maestra.

¿Cuál es la mejor manera de incorporar los cambios a la rama de cambios frontend desde la rama de cambios del backend mientras aún se está revisando?

sul4bh
fuente
14
Bueno, por lo general, las interfaces del proyecto de fondo deben estar claramente definidas. Entonces, cuando comience su implementación de front-end, no debería molestarlo, si la lógica de back-end aún se revisa, ya que puede usar una maqueta.
Herr Derb
17
@HerrDerb Oh, dulce niño de verano ...
cabeza de jardín
44
¿Por qué no puede escribirlo contra su código de fondo aún no revisado?
user253751
¿Tiene su equipo algún tipo de técnica acordada para manejar esta situación? Si no, tal vez debería estar de acuerdo en algo como esto, ya que es una situación bastante común.
Radu Murzea
No hay ninguno. Esa es la razón por la que hice esta pregunta. Recibí muy buenas sugerencias. Probaré las sugerencias y veré cómo me funcionan.
sul4bh

Respuestas:

42

También tengo este problema a veces. Git es muy flexible. Aquí hay una manera de hacerlo.

Su primera sucursal featureAestá en revisión.

Su segunda rama featureBestá en desarrollo y depende del código en la featureArama.

Fusiona la featureArama con la featureBrama.

Si realiza cambios en la featureArama, debe fusionar la featureArama en la featureBrama nuevamente para incorporar los cambios.

También debe asegurarse de fusionarse featureAen el tronco principal primero, de lo contrario, cuando se fusione featureBen el tronco principal, también se fusionará inadvertidamente featureA. Una vez que featureAse haya fusionado con el tronco principal, puede deshacerse de la featureArama ya que ahora featureBsolo depende del tronco principal.

Lo prefiero cuando mis ramas de características no dependen unas de otras, pero a veces lo hacen y hay que rodar con ellas.

Mate
fuente
Esto tiene sentido. ¿Esto permite deshacer la fusión de featureAsobre featureBsi es necesario?
sul4bh
8
No hay operación de deshacer, pero como se menciona en @ 9000, podría hacer una nueva rama y elegir los compromisos que desea featureAsi tuviera que comenzar de nuevo. Es bueno pensar que las ramas de Git son desechables. Son baratos y fáciles, siempre puedes hacer una nueva sucursal. Incluso podría hacer una rama de prueba fuera de su featureBrama si quisiera jugar con algo de lo que no estaba seguro, y luego desecharlo si no funcionó, o fusionarlo nuevamente en su featureBrama si lo hizo.
Matt
99
La fusión creará un desastre que será difícil (no imposible) revertir. Recogería cherry-pick o rebase (es decir: cherry-pick todo en la función A en la base de la función B). Ver la respuesta de 9000.
Pierre.Sassoulas
1
Esto crea una historia compleja que será un problema durante muchos años cuando alguien quiera entender qué código se cambió para la función A y la función B
Ian
2
si la característica A se actualiza, la característica B debe ser modificada sin fusión
Lyndon White
42

Espera, salta la fusión

Para este enfoque, usted no desea combinar su feature_aen feature_brepetidas ocasiones.

Rebasar ha sido mencionado en otras respuestas, pero solo para rebatir cosas master. Lo que quiere hacer en su caso es:

  • Comience feature_bdesde feature_a, es decir:

    git checkout feature_a
    git checkout -b feature_b
    
  • Cada vez que feature_acambia mientras está esperando fusionarse master, usted lo rebase feature_b :

    ... commit something onto feature_a ...
    git checkout feature_b
    git rebase feature_a
    
  • Finalmente, tan pronto como feature_ase haya fusionado master, simplemente obtienes lo nuevo mastery lo rebasas feature_apor última vez:

    git checkout master
    git pull origin master
    git checkout feature_b
    git rebase --onto master feature_a feature_b
    

    Este rebase final injertará todos los commits que cuelgan del feature_acommit (que ahora es irrelevante ya que se ha fusionado master) directamente master. Su feature_bes ahora una rama simple y estándar que va directamente desde master.

EDITAR: inspirado en los comentarios, un poco de advertencia: si necesita hacer algún cambio que afecte a ambas características, asegúrese de hacerlo feature_a(y luego vuelva a redactar como se muestra). No lo haga en dos commits diferentes en ambas ramas, incluso si puede ser tentador; como feature_aes parte de la historia de feature_b, tener el único cambio en dos confirmaciones diferentes será semánticamente incorrecto y posiblemente conducirá a conflictos o "resurrecciones" de código no deseado, más adelante.

AnoE
fuente
2
Con el rebase en feature_avarias ocasiones, es posible que más tarde se encuentre con problemas, cuando feature_ase haya rebaseado mientras tanto. Como resultado de la ejecución git checkout feature_b; git rebase feature_a, puede obtener conflictos o algunas confirmaciones divertidas que contienen confirmaciones que revierten nuevos cambios feature_a. Esto generalmente se puede resolver mediante el uso --interactivey omitiendo los commits tomados de la versión anterior de la otra rama (tuve que hacer esto varias veces recientemente).
maaartinus
@maaartinus, gracias por el aviso, no me he encontrado con tales problemas. Al igual rebaseque muchos más pasos individuales que un simple merge, seguramente hay una posibilidad visiblemente mayor de que cree conflictos; Por otro lado, mergesería semánticamente bastante incorrecto hacerlo en este caso.
AnoE
Supongo mergeque tendría problemas similares o peores (un conflicto no es tan malo como entrar en un cambio no deseado). Veo una rama como una secuencia de cambios deseados precedidos por muchos cambios no relacionados (lógicamente pertenecientes a una rama diferente). Cuando repetidamente rebase con la misma rama, siempre elimino los cambios no relacionados, ya que sé que aparecerán de todos modos (posiblemente en una forma actualizada) y funciona bien.
maaartinus
1
@maaartinus, he agregado un pequeño apéndice sobre esto (para hacer cambios consistentes que deben ir a ambas ramas solo en la rama base, no en dos confirmaciones diferentes).
AnoE
Buena técnica Es como siempre lo hago también. git rebase --ontoFTW: D
Radu Murzea
29

Ya tiene una rama de la que depende cada una de sus características, y que sigue cambiando. Se llama master.

La forma típica para que una rama de características permanezca sincronizada masteres mantenerse al tanto. Cuando mastercambia, normalmente está git fetch origin master:master && git rebase masteren el directorio de trabajo de su sucursal.

Puedes hacer lo mismo con otra rama de características: sigue buscándola y volviendo a marcarla encima.

Si, por alguna razón, necesita mover sus cambios a una rama diferente, puede seleccionar sus confirmaciones, que nunca se mezclan con las confirmaciones de otra rama.

9000
fuente
Pero creo que el escenario es que la característica-b necesita el código que está en la característica-a, la ramificación desde el maestro no será muy útil. ¿Donde debería empezar? ¿Debo pasar de la función-a y mantenerlas sincronizadas hasta que la función-a se reintegra con el maestro, y luego volver a cambiar de maestro a la función-b?
Sinaesthetic
@Sinaesthetic: se puede, por supuesto, la base feature-bde feature-a, y hacer un rebase el tiempo después de tiempo que feature-aestá cambiando. Esta es una forma típica de hacer un gran cambio observable: dividirlo en part-A(basado en master), part-B(basado en part-A) y más si es necesario. Luego haga una solicitud de extracción para cada parte, y los revisores tienen más facilidad para mirar piezas más pequeñas agrupadas lógicamente.
9000
¿importará si vuelvo a basar la parte b con la parte a frente a la parte b con master en términos de relaciones públicas? Solo quiero asegurarme de que mis cambios no muestren los cambios de la parte a como cambios en la parte b. Además, si combino vs. rebase, ¿cómo afectará eso al RP de la parte b? Cada vez que creo entender los efectos, obtengo un resultado diferente jajaja
Sinaesthetic
5

En este caso donde la tarea frontend tiene una dependencia crítica en el código de back-end, y desea comenzar a trabajar en el frontend antes de que el back-end se finalice y se acepte en master, simplemente comenzaría la tarea de front-end como una rama de características que sale del rama de back-end, en lugar de ramificar la interfaz en master.

Una rama de características que dure lo suficiente debe fusionarse en los cambios de maestro ocasionalmente (para asegurarse de que concilie cualquier fusión o conflictos semánticos como parte del trabajo de desarrollo en la rama de características, en lugar de como parte de la "revisión, qa, fusión- "dominar el proceso"). Entonces, lo hace en su rama de front-end, y cuando el trabajo de backend ha sido aceptado para dominar, obtendrá cualquier cambio menor que se haya realizado en el backend como parte de su revisión / aceptación automáticamente, por la misma ruta que usted obtenga cualquier otro cambio de código en el maestro.

Si resulta que la rama del backend necesita mucho más trabajo y continúa cambiando durante un período de tiempo antes de fusionarse con master (por ejemplo, si se encuentran problemas importantes durante la revisión), entonces probablemente desee realizar fusiones periódicas directamente desde la rama de back-end a la rama de front-end (para que no siga basando todo su trabajo de front-end en código de back-end obsoleto). Esto es fácil si eres el único desarrollador que realiza ambas funciones (ya que sabes si tú mismo realizas algún cambio importante), pero incluso si ambas características terminan siendo trabajadas en paralelo por diferentes desarrolladores, debería estar bien; solo tiene que mantenerse en comunicación (lo que necesitaría de todos modos, si está trabajando en tareas en paralelo donde una tiene una dependencia crítica de la otra).

Si resulta que toda la rama de back-end necesita ser abandonada y nunca se fusionará (parece que este sería un acuerdo bastante importante que rara vez sucedería), entonces debes elegir tus compromisos para una nueva rama que sale del maestro sin el trabajo de back-end, o aplica commits inversos que eliminan todo el código de back-end a la rama frontend. Pero como puedo ver, sería más probable que detuviera el trabajo de la interfaz hasta que descubriera qué iba a reemplazar el backend que está tirando y luego decida qué hacer.

Ben
fuente
2

No veo el problema aquí.

Ya tiene esto cada vez con su mastersucursal, que sigue cambiando mientras se desarrollan y fusionan las características.

Entonces, en su ejemplo concreto, primero crea la feature_xxx_backendrama y desarrolla los cambios de back-end. Cuando se hace esto, la sucursal está lista para revisión y se fusionará masteruna vez que se complete la revisión.

Por lo tanto, sólo tiene que iniciar otra rama, feature_yyy_frontend. Probablemente querrá ramificarse directamente desde feature_xxx_backend, para que tenga esos cambios ya en su sucursal. luego, simplemente desarrolle la función de interfaz como la rama master.

Cuando la feature_xxx_backendrama cambia, por ejemplo, porque hay cosas que surgen durante la revisión que deben abordarse, simplemente haga estos cambios y combínelos en la feature_yyy_frontendrama. Luego continúe en la rama frontend.

Una vez que se completa la revisión de la rama back-end, se fusiona master. En este punto, sería aconsejable cambiar la base de la feature_yyy_frontendrama master, de modo que los revisores solo necesiten revisar los nuevos cambios a los que contribuye esta rama master, y no tengan que volver a revisar los cambios realizados para el backend (que ya han sido aprobados )

Esto también se puede hacer cuando tiene dos, tres o más ramas dependientes. Si tiene dos ramas de características de las que depende, simplemente haga una rama derivada que tenga ambas características fusionadas. Rama desde allí, desarrolle la tercera característica, combine ambas ramas de características en el camino cuando cada una de ellas cambie. Cuando ambas características están hechas y se fusionan en la rama derivada, se vuelve a basar en eso, o si se fusionan en maestro, se vuelven a fusionar en maestro.

La reformulación (como se sugirió anteriormente) es realmente poderosa y ayuda a mantener un registro limpio de los cambios, lo que facilita mucho las revisiones.

Poligoma
fuente
2

Como mencionó Polygnome, en realidad puede fusionar su rama frontend con su rama backend en lugar de los maestros. Incluso con la configuración de sucursal actual que tiene ahora, simplemente puede hacer:

git checkout frontend
git merge backend

o simplemente

git merge backend frontend

Sin embargo, tenga en cuenta que si no se aceptan los cambios del backend y se necesita más trabajo, deberá fusionar las actualizaciones del backend en la interfaz para evitar conflictos. Una vez que los cambios son aceptados en el maestro, puede volver a basar su interfaz en el maestro para deshacerse de los commits de fusión de back-end.

Técnicamente, también podría hacer todo con rebase, pero eso arruinará el historial de confirmaciones de su rama frontend. De donde vengo, esto se considera una mala práctica. YMMV

Joris Meys
fuente
"Extraño que nadie mencionó que en realidad se puede fusionar su sucursal frontend con su rama de back-end en lugar de los maestros:" Este ha sido ya mencionado, por ejemplo, en mi propia respuesta.
Polygnome
La interfaz @Polygnome no tiene que ramificarse directamente desde el backend. Ambos pueden ser ramificados del maestro también, pero aún puede fusionarlos. Entonces su respuesta no menciona eso en realidad.
Joris Meys
En realidad, mi respuesta no sugiere que se ramifique directamente desde el backend, solo dice que esa es probablemente la ruta a seguir (ya que de todos modos fusiona esos cambios en la rama frontend).
Polygnome
@Polygnome, entonces entendí mal tu respuesta. Actualizado especialmente para usted :-)
Joris Meys
No sé quién votó en contra de esto, pero dígame dónde me equivoco, para que yo también pueda aprender algo.
Joris Meys
1

La mayoría de las respuestas aquí describen correctamente el proceso de combinar los cambios de la segunda rama a la primera, pero no abordan cómo minimizar la cantidad de conflictos que puede necesitar resolver.

Siempre que tenga dos conjuntos de grandes cambios que desee revisar individualmente (como featureAy featureB), cree un RP que NO esté destinado a fusionarse, sino que obtenga comentarios tempranos sobre un PoC de featureA.

Las personas podrán revisarlo rápidamente (es solo un PoC), y el objetivo es validar el diseño o enfoque general.

Luego, puede seguir trabajando en la función A, crear una solicitud de extracción y ramificar y trabajar en la función B.

La gran diferencia es que ahora puede esperar featureAque no cambie radicalmente: el diseño y el enfoque ya estaban validados. La revisión del código y los cambios requeridos pueden ser sutiles y locales en lugar de "fallas, necesita un enfoque diferente". Esto minimizará la cantidad de trabajo que necesita hacer para luego fusionar featureBel featureAcódigo, independientemente del método que elija.

Alfa
fuente