La rama de Git divergió después del rebase

112

He modificado la base de una rama localmente que ya se envió.

Git advierte que mi rama y el control remoto han divergido y que:

"y tener 109 y 73 confirmaciones diferentes cada una, respectivamente"

¿Al presionar mi rama se resolverá esto, es decir, es de esperar después de una rebase?

Marty Wallace
fuente
Tengo el mismo problema. ¿Podemos decir que "la forma correcta de hacerlo" es reajustar la sucursal local y solo luego presionar?
Mher Didaryan

Respuestas:

154

Cuando reabastece una rama, debe reescribir las confirmaciones para cualquier confirmación que esté por encima de las confirmaciones en la rama en la que está reajustando. Esto se debe a que una de las propiedades de una confirmación es su padre (o padres). Cuando cambia la base, está cambiando el padre de la confirmación local más antigua en su rama y, por lo tanto, cambiando los hash de confirmación de todas sus confirmaciones locales, ya que este cambio surge a través de las confirmaciones de forma transitiva.

Como ya empujó la rama, debería haberse fusionado en la rama de origen, en lugar de rebasar contra ella. Es posible "forzar la inserción" de su nueva rama (usando la -fbandera), pero una inserción normal no funcionará, porque la integridad del historial de las ramas se verá alterada. Si está colaborando con otros en esta rama, forzar el empuje es una mala idea, ya que hará que otros colaboradores se confundan mucho cuando su historial de repente no coincida.

TL; DR: si no está colaborando, empuje la rama usando push -f. Si es así, restablezca la rama al estado anterior y combínela en la rama de origen.

Jason LeBrun
fuente
1
"Como ya empujaste la rama, deberías haberte fusionado en la rama fuente", ¿por qué?
Hammett
1
@HamiltonVerissimo Primera oración de Jason: "Cuando reorganizas una rama, tienes que volver a escribir las confirmaciones para cualquier confirmación que esté por encima de las confirmaciones en la rama en la que estás reajustando". Aunque los cambios capturados en las confirmaciones "anteriores" tienen el mismo contenido lógico, se están aplicando a una base diferente y, por lo tanto, son confirmaciones diferentes con diferentes hashes. Si otros desarrolladores están trabajando desde la rama pre-rebasada, hacer un git push -f sería extremadamente perjudicial para su flujo de trabajo. Por lo tanto, dado que esta rama ha sido transferida a una fuente pública, debería haberse fusionado.
awolf
4
También puede usar push --force-with-lease si no está seguro de si alguien más ya presionó algo.
Consola
1
@ jason-lebrun ¿No es la desventaja de fusionar los cambios anteriores que puede sobrescribir su propio trabajo sin previo aviso? ¿Se detectan los conflictos de fusión de la misma manera que cuando se reajusta? Por ejemplo, si elimino una sección de un archivo en mi rama porque ya no es necesaria, pero alguien más hizo un cambio trivial en la misma sección en el flujo ascendente, como eliminar algunos espacios en blanco o alguna acción global de buscar / reemplazar, no lo haría fusionando eso en la parte superior de mi rama, ¿reemplazar mi eliminación con su versión trivialmente cambiada?
Chris Bloom
1
¿No es mala idea fusionar la otra rama con la tuya? Por ejemplo, fusionar el maestro en una rama de funciones, ¿no creará eso una nueva confirmación para eso? ¿No resultará eso en una confirmación adicional una vez que esta función se ramifique si se fusiona con la maestra más adelante?
Ross
55

Todas sus confirmaciones han cambiado los identificadores, por lo que la desviación no es realmente una divergencia.

Para resolver su problema , debe sobrescribir su sucursal remota:

git push -f origin experiment

http://git-scm.com/book/ch3-6.html

Explicación:

Vea cómo en esta imagen C3 no se pone como C3 después del rebase, sino como C3 '. Esto se debe a que no es exactamente C3, pero tiene todos sus cambios de código.

Rebase

En esta otra imagen, obtienes la imagen de lo que se ve una rebase cuando se trata de un control remoto y por qué hay una desviación.

diverge y git push

En cualquier caso, después de hacer el empuje forzado, le dirá que hizo una (actualización forzada), debería estar bien en ese punto.

Consulte el enlace en la parte superior y busque "git push --force". Verá una explicación más detallada.

mimoralea
fuente
3
Sip. Supongo que esto resuelve el problema. Sin embargo, es posible que el empuje forzado no funcione cuando trabajas con un equipo cuando tu empuje puede sobrescribir cualquier trabajo reciente empujado por otros. Estoy en lo cierto?
Hari Krishna Ganji
Puede que no tenga los efectos deseados. Asegúrate de fusionar tus cambios en "avance rápido" antes de hacer el rebase.
mimoralea
1

Tuve éxito con el rebase diverge para un empujón haciendo lo siguiente:

git checkout mybranch
git pull
git push origin mybranch

El tirón resolvió la divergencia.

ANTES del tirón

Your branch and 'origin/mybranch' have diverged,
and have 2 and 1 different commit(s) each, respectively.

Salida PULL

Fusión realizada por recursiva. mypath / myfile.py | 12 +++++++++++ - 1 archivo modificado, 11 inserciones (+), 1 eliminación (-)

DESPUÉS de tirar

Su rama está por delante de 'origin / mybranch' en 3 confirmaciones.

DESPUÉS DE EMPUJAR

mybranch está 3 por delante de la rama, todavía tiene un mensaje de fusión de solicitud de extracción abierta agregado al historial de confirmación Fusionar rama mybranch de remoto en mybranch

Supongo que esto es probablemente lo que hace el empuje forzado, y no lo he verificado.

Como han dicho los demás, evite una rebase si ya tiene una solicitud de extracción abierta. Estoy proporcionando este ejemplo como algo que funcionó para mí.

zerocog
fuente
1

Esto puede arreglarse sin un empuje forzado rebasando la rama de destino en su rama local actual, cambiando a su rama de destino y luego reajustando su rama local en el objetivo. Esto no difiere ya que las confirmaciones que pueden faltar se agregan y ya no es necesario crearlas. Ejemplo para una explicación más sencilla:

  1. La rama principal se desarrolla
  2. Verifica una nueva característica de rama / doing_stuff
  3. Un miembro del equipo impulsa un nuevo compromiso para desarrollar

Si NO ha actualizado su rama de desarrollo, entonces un "git checkout desarrollar" && "git rebase feature / doing_stuff" funcionará correctamente ya que no se han agregado confirmaciones desde su checkout. Sin embargo, si ha verificado el desarrollo y ha eliminado la nueva confirmación, verá esta divergencia si intenta volver a establecer la base debido a que se ve una nueva confirmación. Una solución fácil sin presionar a la fuerza (por lo general, no es una buena idea en un entorno de equipo) es:

  1. función de pago de git / doing_stuff
  2. desarrollar git rebase
  3. desarrollo de git checkout
  4. función de git rebase / doing_stuff

El rebase del paso 2 trae la confirmación faltante a feature / doing_stuff, por lo que cuando aparece el paso 4, está actualizada y no es necesario crear una nueva confirmación para el cambio.

Esta es una solución que sé que funciona porque me encontré con esto e hice los pasos anteriores para impulsar con éxito el desarrollo sin forzar. Trabajo en un equipo de más de 50 desarrolladores, por lo que está prohibido forzar el impulso de cualquier otra cosa que no sean mis propias ramas de prueba, así que tuve que encontrar una solución.

Chris
fuente