repositorio - Git push rechazado después de la función de rebase de rama
git push origin master (11)
OK, pensé que esto era un simple escenario git, ¿qué me estoy perdiendo?
Tengo una rama master
y una rama feature
. Hago algunos trabajos sobre master
, algunos sobre feature
y luego algunos más sobre master
. Terminé con algo como esto (orden lexicográfico implica el orden de cometer):
A--B--C------F--G (master)
/
D--E (feature)
No tengo ningún problema en git push origin master
para mantener actualizado el master
remoto, ni con la git push origin feature
(cuando está en la feature
) para mantener una copia de seguridad remota para el trabajo de mi feature
. Hasta ahora, estamos bien.
Pero ahora quiero volver a activar la feature
en la parte superior de los F--G
confirmados en el master, así que 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 el que desee realizar una copia de seguridad de la nueva feature
rediseñada con la git push origin feature
debido a que el árbol cambió debido a la redistribución de la base. Esto solo se puede resolver con la git push --force origin feature
.
Odio usar la --force
sin estar segura de que la necesito. Entonces, ¿lo necesito? ¿El cambio de base implica necesariamente que el próximo push
debería ser - --force
?
Esta rama de función no se comparte con ningún otro desarrollador, por lo que no tengo ningún problema de facto con la fuerza de empuje, no voy a perder ningún dato, la pregunta es más conceptual.
¿Qué está mal con un git merge master
en la rama feature
? Esto preservará el trabajo que tenía, mientras lo mantiene separado de la rama de la línea principal.
A--B--C------F--G
/ /
D--E------H
Edit: Ah, lo siento, no leí su declaración de problemas. Necesitarás fuerza mientras realizas una rebase
. Todos los comandos que modifiquen el historial necesitarán el argumento --force
. Esto es una prueba de fallos para evitar que pierda el trabajo (la antigua D
y la E
se perderían).
Así que realizó una git rebase
que hizo que el árbol pareciera (aunque parcialmente oculto, ya que D
y E
ya no están en una rama con nombre):
A--B--C------F--G
/ /
D--E D''--E''
Por lo tanto, cuando intentas impulsar tu nueva rama de feature
(con D''
y E''
en ella), perderías D
y E
A medida que el OP entiende el problema, solo busca una solución mejor ...
¿Qué tal esto como una práctica?
Tenga en la rama de desarrollo de funciones real (donde nunca hace rebase y fuerza), por lo que sus compañeros desarrolladores de funciones no lo odian). Aquí, regularmente tome esos cambios de main con una combinación. Historia más sucia , sí, pero la vida es fácil y nadie se interrumpe en su trabajo.
Tener una segunda rama de desarrollo de características, donde un miembro del equipo de características regularmente empuja todos los compromisos de características, de hecho rebasados, de hecho forzados. Así que casi limpiamente basado en un compromiso maestro bastante reciente. Al completar la función, empujar esa rama en la parte superior del maestro.
Puede que ya haya un nombre de patrón para este método.
El problema es que git push
asume que la sucursal remota puede ser reenviada rápidamente a su sucursal local, es decir, que toda la diferencia entre las sucursales locales y remotas está en que las nuevas confirmaciones locales al final son así:
Z--X--R <- origin/some-branch (can be fast-forwarded to Y commit)
/
T--Y <- some-branch
Cuando realiza git rebase
confirmaciones D y E se aplican a la nueva base y se crean nuevas confirmaciones. Eso significa que después de la rebase tienes algo así:
A--B--C------F--G--D''--E'' <- feature-branch
/
D--E <- origin/feature-branch
En esa situación, la rama remota no se puede reenviar a local. Sin embargo, en teoría, las sucursales locales se pueden fusionar con las remotas (obviamente no las necesita en ese caso), pero como git push
solo realiza el avance rápido, las fusiones y los errores.
Y lo que hace la opción --force
es ignorar el estado de la rama remota y establecerlo en el compromiso que está presionando. Por lo tanto, git push --force origin feature-branch
simplemente reemplaza el origin/feature-branch
con la feature-branch
local.
En mi opinión, la función de rebasar las ramas en el master
y forzarlas a regresar al repositorio remoto está bien siempre y cuando usted sea el único que trabaje en esa rama.
En lugar de usar -f o --force, los desarrolladores deberían usar
--force-with-lease
¿Por qué? Porque comprueba los cambios en la rama remota, lo que es absolutamente una buena idea. Imaginemos que James y Lisa están trabajando en la misma rama de características y Lisa ha impulsado un compromiso. James ahora vuelve a basar su sucursal local y es rechazado cuando intenta empujar. Por supuesto, James piensa que esto se debe a una rebase y utiliza --force y reescribiría todos los cambios de Lisa. Si James hubiera usado "forzar con el arrendamiento", habría recibido una advertencia de que alguien más ha cometido. No veo por qué alguien usaría --force en lugar de --force-with-lease cuando se empuja después de una rebase.
Los siguientes trabajos para mí:
git push -f origin branch_name
y no elimina ninguno de mis codigos.
Pero, si quieres evitar esto, puedes hacer lo siguiente:
git checkout master
git pull --rebase
git checkout -b new_branch_name
entonces puedes elegir todos tus compromisos con la nueva sucursal. git cherry-pick COMMIT ID
y luego presiona tu nueva sucursal.
Mi forma de evitar el empuje forzoso es crear una nueva sucursal y continuar trabajando en esa nueva sucursal y, después de cierta estabilidad, eliminar la antigua rama que se rebasó:
- Rebasando localmente la rama retirada
- Ramificación de la rama rebasada a una nueva rama
- Empujando esa rama como una nueva rama a distancia. y borrando la rama vieja en el control remoto
Otros han respondido a tu pregunta. Si cambias de base una rama, deberás forzarla para empujar esa rama.
Rebase y un repositorio compartido generalmente no se llevan bien. Esto es reescribir la historia. Si otros están usando esa rama o se han ramificado de esa rama, la rebase será bastante desagradable.
En general, la rebase funciona bien para la administración de sucursales locales. La administración remota de sucursales funciona mejor con combinaciones explícitas (--no-ff).
También evitamos la combinación de master en una rama de características. En su lugar, cambiamos de base a master pero con un nuevo nombre de rama (por ejemplo, agregando un sufijo de versión). Esto evita el problema de la rebasación en el repositorio compartido.
Para mi los siguientes sencillos pasos funcionan:
1. git checkout myFeature
2. git rebase master
3. git push --force-with-lease
4. git branch -f master HEAD
5. git checkout master
6. git pull
Después de hacer todo lo anterior, también podemos eliminar la rama myFeature siguiendo el comando:
git push origin --delete myFeature
Puede o no ser el caso de que solo haya un desarrollador en esta rama, es decir, 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 rama, esto debería resolver esto sin una --force, lo que creo que en general es un gran inconveniente de Git.
Una solución para esto es hacer lo que hace el script de combinación de rebasing de msysGit: después de la rebase, fusionar el antiguo jefe de la feature
con -s ours
. Se termina con el gráfico de confirmación:
A--B--C------F--G (master)
/ /
/ D''--E'' (feature)
/ /
/ --
/ /
D--E (old-feature)
... y su 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 eso es correcto ...)
Yo usaría en cambio "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 borra, evita empujar una rama que sale y que contiene una ID de SHA diferente. Estoy borrando solo la rama remota en este caso.