La rebase de GIT requiere volver a comprometer los cambios

Antes que nada, soy nuevo en git branching. No estaba al tanto de que cada twig de característica debería ramificarse desde el master y solo usar la twig de característica de requisito previo con tal relación con la siguiente twig de característica.

Tengo tres twigs. master , feature-1 y feature-2 presionaron un repository de Bitbucket (con el seguimiento de problemas habilitado). El problema es que commits M4 y M5 son commits críticos que todas las twigs deben volver a establecer antes de realizar una fusión (tarea de git rebase )

 M1 -- M2 -- M3 -- M4 -- M5 [master] \ / A1 --- A2 [feature-1] \ B1 -- B2 -- B3 [feature-2] 

El desarrollo de la feature-2 está hecho y ahora se necesita fusionarlo a maestro. Aquí está la precedencia de las tareas que he hecho para feature-2 para volver a establecer la base M4 y M5 commits para feature-2 .

  1. git push – desarrollo de feature-2
  2. git checkout feature-2
  3. git rebase master
  4. Resolver conflictos
  5. git pull

Después de hacer esos pasos me di count después de ejecutar el git status . Tengo que volver a presionar todas las confirmaciones ( feature-2 , M4 , M5 y confirmaciones de conflictos). Bueno, todo lo que tengo que hacer es simplemente hacer git push e iniciar la request de extracción y listo, ¿verdad? Pero eso agregaría otros comentarios de commit de git al rastreador de problemas.

¿Existe alguna manera de volver a establecer la base de la feature-2 para master sin la necesidad de volver a presionar las confirmaciones de la feature-2 , M4 y M5 y el git log debería contener confirmaciones de conflictos?

Actualizar

  • Cambia los detalles de la pregunta para una mejor clarificación

Como ya ha presionado ambas twigs de características, no debe volver a establecer ninguna base. Se desaconseja rotundamente volver a publicar las twigs ya publicadas ya que rompe los repositorys de otros desarrolladores. El motivo es que una rebase es solo una reescritura completa de los commits. Los commits que está networkingefiniendo se vuelven a crear, con contenidos modificados y, lo que es más importante, con hashes diferentes. Esto hace que los nuevos commits sean incompatibles con los antiguos, por lo que quien tenía los viejos termina en conflicto con los nuevos que los reemplazan.

La solución adecuada para esto es simplemente fusionar los cambios. Si bien esto puede no parecer tan bonito, es una acción no destructiva en la que no se modifican las confirmaciones existentes. Todo lo que sucede es que se agregan confirmaciones, lo que no ocasionará problemas al empujar o tirar.

Una vez dicho esto, puede volver a establecer la base y aún publicar las twigs modificadas. Pero para hacerlo, deberá forzar el empuje de las twigs y otros desarrolladores que necesiten esos cambios deberán restablecer sus twigs a las nuevas versiones.


Para incorporar algunos de mis comentarios a continuación en la respuesta: Es importante comprender que en Git, las twigs son solo indicadores de compromisos. Todo el historial, sin twigs, es un gran gráfico acíclico donde los commits solo apuntan a sus commits principales. Entonces, para tomar su ejemplo de la pregunta, esta es la historia, sin ningún puntero de twig:

 A -- B -- C -- D -- E \ / F --- G \ H -- I -- J 

Cada letra representa un compromiso y todas las confirmaciones se conectan a la izquierda son sus padres. Entonces, por ejemplo, el padre de F es A , y C es un compromiso de fusión con los padres B y G

Ahora, si agregamos twigs a esa visualización, simplemente agregamos pointers que apuntan a algunas confirmaciones. Realmente no es nada más (una twig es, literalmente, solo un file que contiene el hash de una confirmación):

  master ↓ A -- B -- C -- D -- E \ / F --- G ← feature-1 \ H -- I -- J ↑ feature-2 

Ahora, imagina que hacemos un compromiso con la twig feature-2 . Agregamos que comprometerse con el tree …

  \ H -- I -- J -- K ↑ feature-2 

… y luego movemos el puntero de la twig uno hacia adelante:

  \ H -- I -- J -- K ↑ feature-2 

Ahora, para comprender lo que sucede durante un empujón, debemos recordar que las twigs remotas también son solo twigs, y como tal solo otro set de pointers. Entonces realmente se ve así:

  \ H -- I -- J ----------- K ↑ ↑ origin/feature-2 feature-2 

Creo que ahora puedes imaginar lo que sucede durante un push: le decimos al repository remoto que actualice su puntero de twig para que apunte a K Pero el server solo tiene J , por lo que debemos darle al server todo para build el tree al que pueda acceder K (de modo que cualquier otro compromiso se encuentre entre ellos y todos los contenidos reales de esos commits). Pero, por supuesto, no necesitamos presionar físicamente J , ni H , ni siquiera A (aunque todas están técnicamente en la twig de feature-2 ya que puede alcanzarlas ); Git es lo suficientemente inteligente como para descubrir qué objects faltan en realidad (puedes ver a Git calculando eso cuando comienzas un empujón).

Entonces, una vez que transferimos los objects faltantes al repository remoto, le pedimos al repository remoto que actualice su puntero feature-1 , por lo que también apuntará a K Y si eso tuvo éxito, también actualizamos nuestra twig remota ( origin/feature-2 ) para que también apunte (solo para sincronizar).

Ahora, la situación es realmente igual con las fusiones. Imagine que fusionamos master en feature-2 (usando git merge master mientras que en feature-2 ):

  master ↓ A -- B -- C -- D -- E ----- \ / \ F --- G ← feature-1 \ \ \ H -- I -- J -- K -- L ↑ feature-2 

Ahora, si queremos presionar la feature-2 , de nuevo necesitamos dar al repository remoto todos los objects que no tiene. Y dado que estamos en una fusión, cometer ahora, necesitamos verificar a todos los padres: Entonces, si el server no tenía K tendríamos que presionar K ; Pero también, si no tiene E , tendríamos que empujar E Y, por supuesto, necesitamos seguir a esos padres nuevamente para asegurarnos de que todos los objects existen en el control remoto. Y una vez hecho esto, simplemente le decimos al control remoto nuevamente que actualice el puntero de sucursal.

Entonces, para resumir: una twig contiene todas las confirmaciones que de alguna manera son accesibles navegando por los padres de sus commits en el tree acíclico. Pero incluso si eso significa que las twigs suelen ser muy "grandes" (en la longitud de la historia), Git solo transferirá esos objects al repository remoto que no posee. Entonces, aunque una fusión puede agregar muchas más confirmaciones a una sucursal, esas no necesariamente tienen que ser transferidas si el control remoto ya las conoce de otra sucursal.


Y finalmente, algunas últimas palabras sobre el rebasado: arriba hicimos git merge master para fusionar la twig master en feature-2 . Si git rebase master lugar, el tree completo se vería así ahora:

  master feature-2 ↓ ↓ A -- B -- C -- D -- E -- H' -- I' -- J' -- K' \ / F --- G ← feature-1 \ H -- I -- J -- K ↑ origin/feature-2 

Como puede ver, hay nuevos compromisos H' , I' , J' y K' . Estas son las confirmaciones reescritas para que comiencen en E (donde el master señaló en el momento de la rebase) en lugar de G Como hemos vuelto a establecer la base, no hay confluencia de compromiso L Y como se aclara arriba, los commits originales aún existen . Es solo que no queda un puntero que los señale; entonces están "perdidos" y eventualmente serán recolectados.

Entonces, ¿cuál es el problema al empujar ahora? La twig remota aún apunta a la K original, pero queremos que apunte a K' ahora. Entonces comenzamos a darle al repository remoto todos los objects que necesita, al igual que antes. Pero cuando le decimos que actualice el puntero de bifurcación, se negará a hacerlo. La razón de esto es que al establecer el puntero a K' , tendría que "retroceder en el historial" e ignorar la existencia de confirmaciones H a K No sabe que los hemos networkingiseñado y tampoco existe un vínculo entre los reescritos y los originales. Entonces, para evitar la pérdida accidental de datos, el control remoto se negará a actualizar el puntero de la bifurcación.

Ahora, puedes forzar empujar la twig. Esto le indicará al repository remoto que actualice el puntero de sucursal aunque hacerlo arrojaría esos commits originales. Entonces haces eso, y la situación se verá así:

  origin/feature-2 master feature-2 ↓ ↓ A -- B -- C -- D -- E -- H' -- I' -- J' -- K' \ / F --- G ← feature-1 

Hasta el momento, todo está bien: ha decidido volver a establecer la base de la bifurcación y le ha dicho al depósito remoto que lo acepte sin cuestionarlo. Pero ahora imagina que quería sacar eso; y mi twig aún apunta a I Así que ejecutar pull hace lo mismo que un push en reversa: el control remoto me da todos los objects necesarios para completar el historial y luego me dice dónde establecer el puntero de la twig. Y en ese momento, mi Git local se niega a hacerlo por la misma razón que el repository remoto hizo eso antes.

Con el impulso anterior, sabíamos que queríamos replace las confirmaciones originales; pero con un tirón no tenemos eso, por lo que ahora estamos obligados a investigar, o preguntar por ahí, si deberíamos simplemente replace nuestra sucursal local, o si hay alguna falla en el control remoto. Y la situación empeora aún más si trabajáramos localmente por nuestra count y quisiéramos fusionarnos ahora.

Y estos problemas le ocurren a todos los que obtuvieron esos commit originales una vez. En general, desea evitar este desorder por completo, por lo que la regla es nunca volver a basar algo que ya haya publicado. Puede volver a establecer la base siempre y cuando nadie más tenga esos compromisos originales, pero tan pronto como ya no sea el caso, será un desastre para todos los involucrados. Entonces una fusión es definitivamente preferida.

Por lo que yo entiendo, las reglas de su base de código (equipo) exigen una nueva base de su twig de características contra el master . Podrías hacerlo diciendo git rebase --onto master A2 feature-2 que significaría "tomar confirmaciones de la característica-2 comenzando con A2 exclusivo y colocarlas encima del maestro". A continuación, puede enviar los cambios directamente al master y soltar o mantener intacta la twig de la feature-2 , de nuevo según las convenciones del flujo de trabajo.

Si, por otro lado, no se exige la rebase, podrías hacer una fusión simple de la feature-2 en el master , presionando el cambio al master , como lo recomienda @poke.

¿Hay alguna manera de rebase la feature-2 para master sin la necesidad de volver a presionar las confirmaciones de la feature-2

No realmente, teniendo en count una rebase, se reproducirán las confirmaciones de la característica 2 en la parte superior de la maestra, dado esto:

 M1 -- M2 -- M3 -- M4 -- M5 [master] \ / \ A1 --- A2 [feature-1] A1' --- A2' \ B1' -- B2' -- B3' [feature-2] 

Como el signo ' indica, todos los commits han cambiado (su SHA1 es diferente).

Como A1 y A2 ya se fusionaron en master , una mejor base de reference sería

 git rebase --onto master A2 feature-2 

Eso conseguiría:

 M1 -- M2 -- M3 -- M4 -- M5 [master] \ / \ A1 --- A2 [feature-1] B1' -- B2' -- B3' [feature-2] 

Deberías git push --force la nueva twig de la feature-2 revisada para actualizar tu request de extracción.

Una inserción forzada debería actualizar una request de extracción en Bitbucket, ya que admite dicha inserción desde el cuarto trimestre de 2012 ( número 4913 ).
Un empuje forzado no tendrá ningún otro efecto adverso, teniendo en count que está empujando una twig hacia su horquilla donde, presumiblemente, usted es el único que envía actualizaciones.
Dado que la request de extracción se actualizará automáticamente con el nuevo historial de la feature-2 , eso no comprometerá dicha request de extracción.