Pregunta Git push rechazado después de rebase de la rama de características


OK, pensé que esto era un simple guion, ¿qué me estoy perdiendo?

tengo un master rama y una feature rama. Hago un trabajo en master, algunos en feature, y luego un poco más en master. Termino con algo como esto (el orden lexicográfico implica el orden de las confirmaciones):

A--B--C------F--G  (master)
       \    
        D--E  (feature)

No tengo ningún problema para git push origin master para mantener el control remoto master actualizado, ni con git push origin feature (cuando en feature) para mantener una copia de seguridad remota para mi feature trabajo. Hasta ahora, estamos bien.

Pero ahora quiero volver a establecer la base feature en la parte superior de la F--G se compromete con el maestro, entonces yo git checkout feature y git rebase master. Sigue bien. Ahora tenemos:

A--B--C------F--G  (master)
                 \
                  D'--E'  (feature)

Problema: el momento en que quiero hacer una copia de seguridad de la nueva rediseñada feature ramificado con git push origin feature, el empuje es rechazado ya que el árbol ha cambiado debido a la rebase. Esto solo puede ser resuelto con git push --force origin feature.

Odio usar --force sin estar seguro de que lo necesito. Entonces, ¿lo necesito? ¿El rebase necesariamente implica que el próximo push debiera ser --forceful?

Esta rama de características no se comparte con ningún otro desarrollador, así que no tengo ningún problema de facto con el impulso de la fuerza, no voy a perder ningún dato, la pregunta es más conceptual.


627
2018-01-20 10:29


origen


Respuestas:


El problema es ese git push asume que la sucursal remota se puede reenviar rápidamente a su sucursal local, es decir, que toda la diferencia entre las sucursales locales y remotas está en local y tiene algunas confirmaciones nuevas al final como las siguientes:

Z--X--R         <- origin/some-branch (can be fast-forwarded to Y commit)
       \        
        T--Y    <- some-branch

Cuando actúas git rebase commits D y E se aplican a la nueva base y se crean nuevos commits. Eso significa que después de rebase tienes algo como eso:

A--B--C------F--G--D'--E'   <- feature-branch
       \  
        D--E                <- origin/feature-branch

En esa situación, la sucursal remota no se puede reenviar rápidamente a local. Sin embargo, teóricamente la rama local se puede fusionar con remota (obviamente, no es necesario en ese caso), sino como git push realiza solo avance rápido fusiona arroja y error.

Y qué --force la opción hace es simplemente ignorar el estado de la sucursal remota y configurarlo para la confirmación que está implementando. Asi que git push --force origin feature-branch simplemente anula origin/feature-branch con local feature-branch.

En mi opinión, la función de rebase se ramifica en master y forzarlos a regresar al repositorio remoto está bien siempre y cuando usted sea el único que trabaje en esa rama.


454
2018-01-20 10:55



En lugar de usar -f o --force los desarrolladores deberían usar

--force-with-lease

¿Por qué? Porque verifica cambios en la sucursal remota, lo cual es una buena idea. Imaginemos que James y Lisa están trabajando en la misma rama de características y Lisa ha presionado un compromiso. James ahora rebases su rama local y es rechazado cuando intenta empujar. Por supuesto, James piensa que esto se debe a la rebase y utiliza --force y reescribiría todos los cambios de Lisa. Si James hubiera usado --force-with-lease, habría recibido una advertencia de que hay commits hechos por otra persona. No veo por qué alguien usaría --force en lugar de--force-with-lease cuando persigue una rebase.


194
2018-05-26 12:02



En cambio, usaría "checkout -b" y es más fácil de entender.

git checkout myFeature
git rebase master
git push origin --delete myFeature
git push origin myFeature

cuando lo eliminas, evitas presionar en una rama que sale que contiene una ID de SHA diferente. Estoy borrando solo la rama remota en este caso.


27
2017-10-21 22:09



Una solución para esto es hacer lo que hace msysGit fusión de rebase la secuencia de comandos hace - después de la rebase, fusionarse en el antiguo jefe de feature con -s ours. Terminas con el gráfico de compromiso:

A--B--C------F--G (master)
       \         \
        \         D'--E' (feature)
         \           /
          \       --
           \    /
            D--E (old-feature)

... y tu empuje de feature será un avance rápido.

En otras palabras, puedes hacer:

git checkout feature
git branch old-feature
git rebase master
git merge -s ours old-feature
git push origin feature

(No probado, pero creo que es correcto ...)


19
2018-01-20 12:13



Puede o no ser el caso que solo haya un desarrollador en esta rama, que ahora (después de la rebase) no esté en línea con el origen / característica.

Como tal, sugeriría usar la siguiente secuencia:

git rebase master
git checkout -b feature_branch_2
git push origin feature_branch_2

Sí, nueva sucursal, esto debería resolver esto sin una --force, que en general creo que es una gran desventaja de git.


14
2017-10-28 07:36



Otros han respondido tu pregunta. Si restabas una bifurcación necesitarás forzar para empujar esa rama.

Rebase y un repositorio compartido generalmente no se llevan bien. Esto es reescribir el historial. Si otros están usando esa rama o se han ramificado de esa rama, la rebase será bastante desagradable.

En general, rebase funciona bien para la administración de la sucursal local. La administración remota de sucursales funciona mejor con fusiones explícitas (--no-ff).

También evitamos fusionar el maestro en una rama de características. En cambio, rebase a master, pero con un nuevo nombre de rama (por ejemplo, agregar un sufijo de versión). Esto evita el problema de rebase en el repositorio compartido.


11
2018-01-20 16:29



¿Qué pasa con un git merge master sobre el feature ¿rama? Esto preservará el trabajo que tenía, mientras lo mantiene separado de la rama principal.

A--B--C------F--G
       \         \
        D--E------H

Editar: Ah, lo siento, no leí tu declaración del problema. Necesitarás fuerza al realizar un rebase. Todos los comandos que modifican el historial necesitarán --force argumento. Esto es una prueba de seguridad para evitar que pierda el trabajo (el antiguo D y E estaría perdido).

Entonces hiciste una git rebase que hizo que el árbol se vea como (aunque parcialmente oculto como D y E ya no están en una rama nombrada):

A--B--C------F--G
       \         \
        D--E      D'--E'

Entonces, cuando intentes empujar tu nuevo feature rama (con D' y E' en él), perderías D y E.


8
2018-01-20 10:35



Mi manera de evitar el impulso de la fuerza es crear una nueva rama y continuar trabajando en esa nueva rama y, después de cierta estabilidad, eliminar la rama anterior que fue reestablecida:

  • Rebase la sucursal desprotegida localmente
  • Ramificación de la rama rebasada a una nueva rama
  • Empujando esa rama como una nueva rama a remota. y borrar la rama anterior en el control remoto

7
2018-06-19 07:00