Git rechazado sin avance rápido

88

Siento que esta pregunta se ha hecho muchas veces, pero la solución suele ser "Eliminé el directorio y volví a hacer mi trabajo con una nueva compra". Hice una confirmación y empuje, pero me di cuenta de que me refería al número de ticket incorrecto en el mensaje de confirmación. Así que busqué en SO una solución rápida y terminé escribiendo lo siguiente en la terminal:

$ git reset --soft HEAD^
$ git commit -m "... correct message ..."

El único problema es que recibo el siguiente mensaje de error:

To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

Estoy usando el modelo git-flow y estoy trabajando en la rama de desarrollo. ¿Cómo puedo volver a fusionar las cosas para hacer feliz a git de nuevo?

rynmrtn
fuente

Respuestas:

52

Fuerza git push:

git push origin +develop
Alan Haggai Alavi
fuente
24
Esa es una solución, pero lea el comentario de Brian Campbell para que comprenda lo que está haciendo antes de usar esto.
thelem
5
git push origin + master
Aniket Thakur
Consulte también la nota sobre receive.denyNonFastForwardsen la respuesta de Brian Campbell : +o --forcepuede que no sea lo suficientemente contundente, dependiendo de cómo ellos, sean quienes sean, han configurado su repositorio de Git.
torek
174

Si se presiona una confirmación al servidor, y luego volver a escribir que se comprometen a nivel local (con git reset, git rebase, git filter-branch, o cualquier otra manipulación de la historia), y luego empujados que reescrita cometen una copia de seguridad en el servidor, se le arruinar cualquier otra persona que se había detenido. He aquí un ejemplo; digamos que ha comprometido A y lo ha enviado al servidor.

- * - * - A <- maestro

- * - * - A <- origen / maestro

Ahora decides reescribir A, de la forma que mencionaste, reiniciando y volviendo a confirmar. Tenga en cuenta que esto deja una confirmación pendiente, A, que eventualmente será recolectada como basura ya que no es accesible.

-*-*-UNA
    \
     A '<- maestro

- * - * - A <- origen / maestro

Si alguien más, digamos Fred, se retira masterdel servidor mientras haces esto, tendrá una referencia a A, desde la cual podría comenzar a trabajar:

- * - * - A '<- maestro

- * - * - A <- origen / maestro

- * - * - AB <- fred / master

Ahora bien, si pudiera empujar su A 'al origen / maestro, lo que crearía un avance no rápido, no tendría A en su historial. Entonces, si Fred intentara tirar nuevamente, de repente tendría que fusionarse y volvería a presentar el compromiso A:

- * - * - A '<- maestro

- * - * - A <- origen / maestro

- * - * - AB- \ 
    \ * <- fred / maestro
     UNA'--/

Si Fred se da cuenta de esto, entonces podría hacer un cambio de base, lo que evitaría que la confirmación A reapareciera nuevamente. Pero tendría que darse cuenta de esto y recordar hacer esto; y si tiene más de una persona que derribó A, todos tendrían que volver a basarse para evitar que el compromiso A adicional en el árbol.

Por lo tanto, generalmente no es una buena idea cambiar el historial en un repositorio del que otras personas obtienen. Sin embargo, si sabe que nadie más está extrayendo de ese repositorio (por ejemplo, es su propio repositorio privado, o solo tiene otro desarrollador trabajando en el proyecto con el que puede coordinarse fácilmente), entonces puede forzarlo actualizar ejecutando:

git push -f

o

git push origin +master

Ambos ignorarán la verificación de un empuje que no es de avance rápido y actualizarán lo que hay en el servidor a su nueva revisión A ', abandonando la revisión A para que eventualmente se recolecte basura.

Es posible que los empujes forzados estén completamente deshabilitados con la receive.denyNonFastForwardsopción de configuración. Esta opción está habilitada de forma predeterminada en los repositorios compartidos. En ese caso, si realmente desea forzar un envío, la mejor opción es eliminar la rama y volver a crearla con git push origin :master; git push origin master:master. Sin embargo, la denyNonFastForwardsopción está habilitada por un motivo, que se describe anteriormente; en un repositorio compartido, significa que ahora todos los que lo utilizan deben asegurarse de volver a basarse en el nuevo historial.

En un repositorio compartido, generalmente es mejor colocar nuevas confirmaciones en la parte superior que solucionen cualquier problema que tenga; puede usar git revertpara generar confirmaciones que deshacerán los cambios de confirmaciones anteriores.

Brian Campbell
fuente
gran educación, y al final obtuviste el comando correcto, pero mi rama se llamó desarrollar (basado en git-flow), y el otro tipo puso +developsu comando, por lo que el cheque es para él. Tienes una cantidad astronómica de puntos de todos modos: P
rynmrtn
8
O use el menos crípticogit push --force
Bennett McElwee
3
@Panique Está tratando de permitir que varias personas trabajen en una base de código grande y compleja al mismo tiempo, sin bloquearse entre sí (permitiendo que solo una persona trabaje en ella a la vez) y sin que los cambios se sobrescriban entre sí. Necesita que cada persona pueda realizar cambios de forma independiente y fusionar esos cambios. La combinación (ya sea manual o automática) puede presentar problemas inesperados; por lo que desea conservar la mayor cantidad de información posible para poder averiguar qué sucedió si salió mal. Esto es intrínsecamente complejo; no está sucio, solo es un problema difícil.
Brian Campbell
Probé las opciones -f y + para reescribir el historial de repositorios remoto. En ambas opciones, encontré un problema de no avance rápido. [5:05 PM] $ git push -f origin local_A: remote_A Contando objetos: 35, hecho. Compresión delta utilizando hasta 2 subprocesos. Comprimir objetos: 100% (18/18), hecho. Objetos de escritura: 100% (21/21), 7,41 KiB, hecho. Total 21 (delta 9), reutilizado 0 (delta 0) remoto: para evitar perder el historial, se rechazaron las actualizaciones que no son de avance rápido. Combine los cambios remotos (por ejemplo, 'git pull') antes de presionar nuevamente. Consulte la sección 'Nota sobre los avances rápidos' de 'git push --help' para obtener más detalles.
Srikanth
4
@Srikanth Es posible deshabilitar completamente los empujes forzados con la receive.denyNonFastForwardsopción de configuración. Esta opción está habilitada de forma predeterminada en los repositorios compartidos. En ese caso, si realmente desea forzar una inserción, la mejor opción es eliminar la rama y volver a crearla con git push origin :remote_A; git push origin local_A:remote_A. Pero lea lo que escribí anteriormente sobre por qué es una mala idea hacer este tipo de flujo de trabajo en un repositorio compartido. Debe intentar hacer esto solo si tiene algo que cause problemas graves en la confirmación que está tratando de eliminar o reescribir.
Brian Campbell
14

Es posible que tenga que hacer un git pull, que PUEDE fusionar automáticamente las cosas por usted. Entonces puedes comprometerte de nuevo. Si tiene conflictos, le pedirá que los resuelva.

Tenga en cuenta que debe especificar de qué rama extraer si no ha actualizado su gitconfig para especificar ...

Por ejemplo:

git pull origin develop:develop
Tony
fuente
Todavía estoy loco por el no avance rápido. ¿Alguna idea sobre cómo obligarlo a fusionarse? ! [rejected] develop -> develop (non-fast-forward)
rynmrtn
Creo que el interruptor es -f, pero podría estar equivocado. kernel.org/pub/software/scm/git/docs/git-pull.html
Tony
Esto funciona parcialmente. Sin embargo, no veo las actualizaciones en github (muestra la confirmación anterior como la más reciente incluso con a git push origin develop)
rynmrtn
7

Estaba usando EGit y también enfrenté este problema. Intenté con rebasela rama actual y funcionó.

Nguyen Minh Binh
fuente