no puede presionar para ramificarse después de rebase

131

Usamos git y tenemos una rama maestra y ramas de desarrollo. Necesito agregar una nueva característica y luego volver a crear los commits en master, luego empujar master al servidor CI.

El problema es que si tengo conflictos durante el rebase no puedo pasar a mi rama de desarrollador remoto (en Github) después de que se complete el rebase, hasta que retire mi rama remota. Esto provoca confirmaciones duplicadas. Cuando no hay conflictos, funciona como se esperaba.

pregunta: después de la resolución de conflictos y rebase, ¿cómo sincronizo mis ramas de desarrollador local y remoto sin crear confirmaciones duplicadas?

Preparar:

// master branch is the main branch
git checkout master
git checkout -b myNewFeature

// I will work on this at work and at home
git push origin myNewFeature

// work work work on myNewFeature
// master branch has been updated and will conflict with myNewFeature
git pull --rebase origin master

// we have conflicts
// solve conflict
git rebase --continue

//repeat until rebase is complete
git push origin myNewFeature

//ERROR
error: failed to push some refs to '[email protected]:ariklevy/dropLocker.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

// do what git says and pull
git pull origin myNewFeature

git push origin myNewFeature

// Now I have duplicate commits on the remote branch myNewFeature

EDITAR

Parece que esto interrumpirá el flujo de trabajo:

developer1 trabajando en myNewFeature developer2 trabajando en hisNewFeature ambos usan master como rama principal

developer2 combina myNewFeature en hisNewFeature

developer1 vuelve a redactar, resuelve conflictos y luego fuerza los empujes a la rama remota para myNewFeature

un par de días después, developer2, fusiona myNewFeature en suNewFeature nuevamente

¿Esto hará que los otros desarrolladores odien el desarrollador1?

Mate
fuente
No es una solución sino un pensamiento. ¿quién es we? ¿Estás en un equipo de más que solo tú? theydiga (las personas que saben más que yo) que si comparte su código, entonces no debería estar usando rebase. ¿Por qué no estás haciendo git pully git merge?
AdamT
lo sentimos, nosotros = equipo de desarrollo
Matt
1
así que sí, probablemente no debería ser rebase cuando se comparte código. eso puede llevarlo a tener que hacer cosas como las que se enumeran a continuación ( forceel empuje)
AdamT
oh lo siento, cuando dicen rewriting history, eso es unrebase
AdamT
Como dijo una rama de su desarrollo de su propia por lo que no debería ser un problema a menos que alguien se esperaba que de combinación que en.
Learath2

Respuestas:

93

Primero, usted y aquellos con los que está trabajando deben acordar si una rama de tema / desarrollo es para desarrollo compartido o solo para usted. Otros desarrolladores saben que no deben fusionarse en mis ramas de desarrollo porque serán modificadas en cualquier momento. Por lo general, el flujo de trabajo es el siguiente:

o-----o-----o-----o-----o-----o       master
 \
   o-----o-----o                      devel0
                \
                  o-----o-----o       devel1

Luego, para mantenerme actualizado con el control remoto, haré lo siguiente:

 git fetch origin
 git checkout master
 git merge --ff origin/master

Hago esto por dos razones. Primero porque me permite ver si hay cambios remotos sin necesidad de cambiar de mi rama de desarrollo. En segundo lugar, es un mecanismo de seguridad para asegurarse de no sobrescribir ningún cambio no guardado / confirmado. Además, si no puedo avanzar rápidamente a la fusión con la rama maestra, eso significa que alguien ha cambiado el nombre del maestro remoto (por lo que deben ser azotados severamente) o accidentalmente me comprometí con el maestro y necesito limpiar mi extremo.

Luego, cuando el control remoto haya cambiado y lo haya enviado rápidamente a la última versión, volveré a redactar:

git checkout devel0
git rebase master
git push -f origin devel0

Otros desarrolladores entonces saben que necesitarán volver a crear sus ramas de desarrollo en mi último:

git fetch <remote>
git checkout devel1
git rebase <remote>/devel0

Lo que resulta en una historia mucho más limpia:

o-----o                                 master
       \
         o-----o-----o                  devel0
                      \
                        o-----o-----o   devel1

No combine los compromisos de ida y vuelta a su antojo. No solo crea confirmaciones duplicadas y hace que el historial sea imposible de seguir, sino que encontrar regresiones de un cambio específico se vuelve casi imposible (por eso estás usando el control de versiones en primer lugar, ¿verdad?). El problema que tienes es el resultado de hacer esto.

También parece que otros desarrolladores pueden estar comprometiéndose con sus ramas de desarrollo. ¿Puedes confirmar esto?

El único momento para fusionarse es cuando la rama de su tema está lista para ser aceptada master.

En otros comentarios. Si varios desarrolladores se comprometen con el mismo repositorio, todos deberían considerar tener ramas con nombre para distinguir entre las ramas de desarrollo de desarrolladores. Por ejemplo:

git branch 'my-name/devel-branch'

Por lo tanto, todas las ramas temáticas de los desarrolladores residen dentro de su propio conjunto anidado.

Trevor Norris
fuente
1
"También parece que otros desarrolladores pueden estar comprometiéndose con sus ramas de desarrollo. ¿Puede confirmar esto?" SÍ son ...
Matt
También me has llamado la atención sobre otro tema. Trabajando entre la oficina y el hogar. Hago fusiones en ambos lugares y, al final del día, presiono para poder continuar desde donde lo dejé. Luego, cuando llega el momento de rebase, todos esos commits crean confusión. Necesito tratar mis ramas como una rama y rebase
Matt
@ Matt Sí, esos dos problemas realmente arruinarán tu flujo de trabajo. Para el primero, comunicaría a los otros desarrolladores que solo el propietario puede comprometerse con una ramificación con nombre (por ejemplo, 'mate / desarrollo'). En mi humilde opinión, no hay dos desarrolladores deben comprometerse con la misma rama de todos modos. Solo crea confusión. Para lo posterior, el rebase y el empuje forzado deberían mantener las dos ubicaciones actualizadas.
Trevor Norris
Gran respuesta. Tengo una pregunta secundaria, ¿por qué estás usando la --forcebandera cuando lo haces git push -f origin devel0?
Nobita
2
@Nobita Cuando a git pushno puede avanzar rápidamente (es decir, el historial de sha no coincide), debe forzar la pulsación para sobrescribir el historial anterior con el nuevo historial generado a partir de git rebase.
Trevor Norris
50

Debe forzar el empuje ya que ha movido las confirmaciones más abajo de la línea, git espera que agregue confirmaciones a la punta de la rama. git push -f origin myNewFeatureArreglará tu problema.

Consejo: Arriba hay un uso legítimo de empuje forzado. Nunca reescribas la historia en un repositorio de acceso público o mucha gente te odiará.

Learath2
fuente
1
Considero que esta es la forma más óptima de mantener el flujo de trabajo.
Syed Priom
1
Gracias amigo. Utilicé este comando para forzar a mi sucursal local reforzada a la misma sucursal remota.
wei
11
usar git push --force-with-leasees mucho más seguro que usargit push --force
git push --force-with-lease origin HEAD- suponiendo que su sucursal objetivo ya esté
marcada
31

Lo principal a tener en cuenta aquí es lo que están haciendo pull y rebase detrás de escena.

Un tirón básicamente hará dos cosas: buscar y fusionar. Cuando incluye --rebase, hará una nueva versión en lugar de la fusión.

Un rebase es más o menos como esconder todos sus cambios locales desde que se bifurcó, reenviando rápidamente su rama al último commit en el objetivo y desarmando sus cambios en orden en la parte superior.

(Esto explica por qué puede obtener múltiples avisos de resolución de conflictos al hacer un rebase versus la única resolución de conflicto que puede obtener con una fusión. Tiene la oportunidad de resolver un conflicto en CADA confirmación que se está rebase para preservar sus confirmaciones. )

Nunca deseará impulsar cambios modificados a ramas remotas, ya que esto está reescribiendo el historial. Por supuesto, nunca es un poco fuerte, ya que casi siempre hay excepciones. El caso de que necesite mantener una versión remota de su repositorio local para trabajar en un entorno específico, por ejemplo.

Esto requerirá que empuje los cambios de base a veces usando la fuerza:

git push -f origin newfeature

O, en algunos casos, su administrador puede haber eliminado la capacidad de forzar, por lo que debe eliminar y volver a crear:

git push origin :newfeature
git push origin newfeature

En cualquier caso, debe estar absolutamente seguro de saber lo que está haciendo si alguien más está colaborando con usted en su sucursal remota. Esto puede significar que trabajas en conjunto inicialmente con fusiones y vueltas a unir en un formato de confirmación más manejable justo antes de ir a master y eliminar tu rama de trabajo.

Recuerde que casi siempre puede recurrir al GC de git aprovechando:

git reflog

Este es un GRAN salvavidas, ya que puede restablecerlo a un estado más estable si se pierde en toda su gestión de rebase / conflicto.

Matthew Sanders
fuente
La opción de eliminar y recrear anterior funcionó muy bien para mí. ¡No se permite forzar en mi repositorio!
Simon Holmes
2

Necesita realizar un empuje forzado, es decir git push -f origin myNewFeature

Ah, y es mejor que te asegures de que las personas no basen nada en tu rama de desarrollo; por lo general, no se supone que publiques ramas en las que estás reescribiendo el historial (o más bien no reescribes el historial una vez publicado). Una forma sería usar un nombre de sucursal como wip/myNewFeaturey luego mencionar que las wipsucursales serán modificadas para dominar de vez en cuando.

ThiefMaster
fuente
usar git push --force-with-leasees mucho más seguro que usargit push --force
@MrCholo La gente no comenzará a usar esto hasta que git agregue una opción corta como -fpara un empuje forzado normal :)
ThiefMaster
ja, sí, lo usé en un script automatizado aunque
2

La respuesta general que ya se ha dado, para usar git push -f origin myNewFeaturecuando se empujan cambios modificados, es un buen punto de partida. Estoy escribiendo esta respuesta para abordar la edición sobre si interrumpirá su flujo de trabajo.

Si suponemos que se va a utilizar git pull --rebase ...(o alguna variación sobre el mismo), seguido de una fuerza de empuje para la rama remota, a continuación, lo que rompe el flujo de trabajo en su ejemplo se Developer2 está fusionando myNewFeatureen hisNewFeature. Tiene sentido poder cambiar la base de su propia rama de características siempre que nadie más esté trabajando en esa rama, por lo que necesita reglas para delimitar el territorio de la rama.

Puede evitar esto mediante a) establecer una regla de la que solo se fusiona master, ob) crear una developrama colectiva , en la que basará su propia myNewFeaturerama, y ​​establecer una regla de la que solo se fusionará develop. masterluego se reservará solo para hitos o lanzamientos (o como quiera que quiera configurarlo), y developserá donde presione cada función cuando esté lista para integrarse en otras ramas de funciones.

Creo que esto podría considerarse una versión simplificada del flujo de trabajo de Gitflow.

cosmicFluke
fuente
1

Estoy de acuerdo con MrCholo , y tal vez Trevor Norris podría considerar actualizar su buena respuesta para reemplazar

git push -f origin devel0

con

git push --force-with-lease origin devel0
Sylvain Lesage
fuente