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

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

Tengo una twig master y una twig de feature . Trabajo en master , otros en feature y luego en master . Termino con algo como esto (el order lexicográfico implica el order de las confirmaciones):

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

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

Pero ahora quiero reajustar la feature en la parte superior de la F--G compromete en el maestro, por lo que tengo la git checkout feature y git rebase master . Sigue bien. Ahora tenemos:

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

Problema: en el momento en que quiero hacer una copy de security de la nueva feature reescalada ramificada con la git push origin feature envío de git push origin feature , la inserción es rechazada ya que el tree ha cambiado debido a la rebase. Esto solo se puede resolver con la function git push --force origin feature .

Odio usar --force sin estar seguro de que lo necesito. Entonces, ¿lo necesito? ¿El replanteamiento implica necesariamente que el próximo push debería ser --force ful?

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

El problema es que 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 realiza 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 twig local se puede fusionar con la remota (obviamente, no es necesario en ese caso), pero como git push solo realiza fusiones rápidas, arroja errores.

Y lo que --force opción hace es simplemente ignorar el estado de la sucursal remota y configurarlo en la confirmación que está introduciendo. Así que git push --force origin feature-branch simplemente anula origin/feature-branch con local feature-branch .

En mi opinión, la function de reescalar twigs en el master y la fuerza, empujándolas hacia el repository remoto está bien, siempre y cuando usted sea el único que trabaje en esa twig.

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 twig de características y Lisa ha empujado un compromiso. James ahora rebases su twig 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.

Una solución para esto es hacer lo que hace la secuencia de commands de fusión de reference de msysGit: después de la rebase, combine en la cabeza anterior de la 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 su impulso 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 …)

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 twig que sale que contiene una ID de SHA diferente. Estoy borrando solo la twig remota en este caso.

Puede o no ser el caso que solo haya un desarrollador en esta twig, 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.

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

Rebase y un repository compartido generalmente no se llevan bien. Esto es reescribir el historial. Si otros están usando esa twig o se han ramificado de esa twig, 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 twig de características. En cambio, rebase a master, pero con un nuevo nombre de twig (por ejemplo, agregar un sufijo de versión). Esto evita el problema de rebase en el repository compartido.

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

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

Editar: Ah, lo siento, no leí su statement de problema. Necesitarás fuerza al realizar una rebase . Todos los commands que modifican el historial necesitarán el argumento --force . Esto es seguro para evitar que pierda el trabajo (se perderían los antiguos D y E ).

Así que realizó una git rebase que hizo que el tree se vea como (aunque parcialmente oculto ya que D y E ya no se encuentran en una twig con nombre):

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

Por lo tanto, cuando intente insert su nueva twig de feature (con D' y E' en ella), perderá D y E

Lo siguiente funciona para mí:

git push -f origin branch_name

y no elimina ninguno de mi código.

Pero, si desea evitar esto, puede hacer lo siguiente:

 git checkout master git pull --rebase git checkout -b new_branch_name 

entonces puedes seleccionar todos tus compromisos para la nueva sucursal. git cherry-pick COMMIT ID y luego presione su nueva twig.

Como OP comprende el problema, solo busca una solución más agradable …

¿Qué tal esto como una práctica?

  • Tener en la twig de desarrollo de características real (donde nunca rebase y force-push, para que los desarrolladores de sus compañeros no lo odien). Aquí, regularmente toma esos cambios de main con una combinación. Historia Messier , sí, pero la vida es fácil y nadie se interrumpe en su trabajo.

  • Tener una segunda twig de desarrollo de características, donde un miembro del equipo de la característica impulsa todos los commits de características, de hecho re-basado, de hecho forzado. Así que está basado casi limpiamente en un compromiso maestro bastante reciente. Cuando la function esté completa, empuja esa twig sobre la parte superior del maestro.

Puede haber un nombre de patrón para este método ya.

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

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