¿Deshacer una fusión por solicitud de extracción?

159

Alguien aceptó una solicitud de extracción que no deberían haber recibido. Ahora tenemos un montón de código roto fusionado. ¿Cómo deshacer una solicitud de extracción? Iba a revertir los cambios al commit justo antes de la fusión, pero noté que se fusionó en un montón de commits. Así que ahora hay todos estos compromisos de esta persona desde días antes de la fusión. ¿Cómo deshaces esto?

Será
fuente
77
A pesar del consejo de la respuesta aceptada, POR FAVOR no fuerce a un repositorio si el repositorio se comparte con alguien más. Corre el riesgo de arruinar el trabajo que otros han hecho, y GitHub puede continuar mostrando que esa solicitud de extracción se ha fusionado. Otra respuesta a esta pregunta explica una forma más segura de deshacer una solicitud de extracción.
alxndr
2
Nota: al menos ahora (junio de 2014), GitHub propone el botón "Revertir" en su GUI web de solicitud de extracción. Vea mi respuesta a continuación
VonC
1
El problema con el botón de reversión es que crea una nueva confirmación como inversa a la solicitud de extracción, lo que significa que si finalmente desea fusionar estos cambios, usar el botón "Revertir" puede hacer que esto sea mucho más difícil.
FluffySamurai

Respuestas:

159

Hay una mejor respuesta a este problema, aunque podría desglosarlo paso a paso.

Deberá buscar y verificar los últimos cambios ascendentes, por ejemplo:

git fetch upstream
git checkout upstream/master -b revert/john/foo_and_bar

Echando un vistazo al registro de confirmación, debería encontrar algo similar a esto:

commit b76a5f1f5d3b323679e466a1a1d5f93c8828b269
Merge: 9271e6e a507888
Author: Tim Tom <[email protected]>
Date:   Mon Apr 29 06:12:38 2013 -0700

    Merge pull request #123 from john/foo_and_bar

    Add foo and bar

commit a507888e9fcc9e08b658c0b25414d1aeb1eef45e
Author: John Doe <[email protected]>
Date:   Mon Apr 29 12:13:29 2013 +0000

    Add bar

commit 470ee0f407198057d5cb1d6427bb8371eab6157e
Author: John Doe <[email protected]>
Date:   Mon Apr 29 10:29:10 2013 +0000

    Add foo

Ahora desea revertir toda la solicitud de extracción con la capacidad de revertir más tarde. Para hacerlo, deberá tomar la ID de la confirmación de fusión .

En el ejemplo anterior, la confirmación de fusión es la principal donde dice "Solicitud de extracción fusionada # 123 ..." .

Haga esto para revertir los dos cambios ( "Agregar barra" y "Agregar foo" ) y terminará en una confirmación revocando toda la solicitud de extracción que puede volver a anular más adelante y mantener limpio el historial de cambios:

git revert -m 1 b76a5f1f5d3b323679e466a1a1d5f93c8828b269
errores
fuente
66
Esta debería ser la respuesta correcta. Hay una referencia en la página de manual de git-revert a más detalles de la lista de correo de git aquí kernel.org/pub/software/scm/git/docs/howto/…
Justin Hamade
2
¿Por qué el git checkout upstream/master -b revert/john/foo_and_bar? ¿Qué hace exactamente?
Magne
44
@ Magne: está creando una nueva rama para realizar la reversión, que luego puede elegir dónde fusionar la reversión. Básicamente solo te da más control sobre qué hacer con la sucursal. En mi caso, envié una nueva solicitud de extracción de esta rama "fija" que contiene la reversión a nuestra rama de desarrollo, lo que significa que mi nueva solicitud de extracción también podría revertirse si fuera necesario. Esto se hizo para un lanzamiento en el que decidimos sacar el primer borrador de una función que fue reprogramada. Sin código incorrecto, simplemente no voy en esta versión.
Daniel Nalbach
3
Aprendí una dura lección sobre este. Impulsamos una característica a nuestra rama de desarrollo, pero nos dimos cuenta de que había problemas de datos y revertimos directamente en el desarrollo. Más tarde, cuando se arreglaron las cosas, queríamos agregar nuevas características de desarrollo a esta rama para probar su compatibilidad con esta característica antes de presionar, por lo que fusioné el desarrollo nuevamente a la rama de características. Esto también aplicó la confirmación de reversión, que anotó todos los cambios realizados en la rama de características. > <
Greg
86

Mire su gráfico de compromiso (con gitk o un programa similar). Verá confirmaciones de la solicitud de extracción, y verá sus propias confirmaciones y una confirmación de fusión (si no fue una combinación de avance rápido). Solo tiene que encontrar el último de sus propios commits antes de la fusión y restablecer la rama a este commit.

(Si tiene el reflog de la rama, debería ser aún más fácil encontrar el commit antes de la fusión).


(Editar después de más información en los comentarios :)

Bien, veamos el gráfico:

captura de pantalla 1

Supongo que la última confirmación (más a la derecha) fue su fusión incorrecta por solicitud de extracción , que fusionó la línea azul que se ve aquí. Su última buena confirmación sería la anterior en la línea negra, aquí marcada en rojo:

ingrese la descripción de la imagen aquí

Restablezca esta confirmación, y debería estar bien.

Esto significa que en su copia de trabajo local haga esto (después de asegurarse de que no tiene más cosas sin confirmar, por ejemplo, por git stash):

git checkout master
git reset --hard 7a62674ba3df0853c63539175197a16122a739ef
gitk 

Ahora confirme que realmente está en la confirmación que marqué allí, y no verá ninguna de las cosas extraídas en su ascendencia.

git push -f origin master

(si su control remoto de github se llama origin, de lo contrario cambie el nombre).

Ahora todo debería verse bien en Github también. Los commits aún estarán en su repositorio, pero ninguna rama podrá acceder a ellos, por lo que no debería causar ningún daño allí. (Y seguirán en el repositorio de RogerPaladin, por supuesto).

(Puede haber una forma específica de Github solo en la web para hacer lo mismo, pero no estoy muy familiarizado con Github y su sistema de gestión de solicitudes de extracción).

Tenga en cuenta que si alguien más podría haber extraído a su maestro con el commit incorrecto, entonces tienen el mismo problema que usted tiene actualmente y realmente no pueden contribuir de nuevo. antes de reiniciar a su nueva versión maestra.

Si es probable que esto haya sucedido, o simplemente desea evitar cualquier problema, use el git revertcomando en lugar de git reset, para revertir los cambios con una nueva confirmación, en lugar de volver a establecer una anterior. (Algunas personas piensan que nunca debería reiniciar con las ramas publicadas). Vea otras respuestas a esta pregunta sobre cómo hacerlo.

Para el futuro:

Si solo desea algunos de los commits de la rama de RogerPaladin, considere usar en cherry-picklugar de merge. O comuníquese con RogerPaladin para moverlos a una sucursal separada y enviar una nueva solicitud de extracción.

Paŭlo Ebermann
fuente
Pero tenemos un montón de compromisos entre la fusión y su primer compromiso. Entonces, como tenemos el commit de fusión, nuestros propios commits y luego otro commit de él. Parece que se fusionó en compromisos muy antiguos suyos.
Será el
Sí, se fusionará en todo lo que sea un ancestro del commit combinado (y no sea un ancestro de tu commit). Esto no debería obstaculizar su reinicio: los commits no se reordenarán por sí mismos, si no realizó un rebase posterior.
Paŭlo Ebermann
1
Sí, ahora se ve bien (aparte de la extraña fusión en sí mismo , pero esto podría ser una falla en el software de gráficos de red). :-) Me alegro de poder ayudar.
Paŭlo Ebermann
66
Creo que esto puede ser problemático si alguien ha realizado los commits incorrectos y luego envían una solicitud de extracción que contiene los mismos commits incorrectos, por lo que se escabullen pero en el repositorio. ¿No sería más seguro crear una nueva confirmación que invierta las confirmaciones incorrectas? De esa manera, si las confirmaciones erróneas se han llevado a otras ramas / bifurcaciones, ¿serán efectivamente eliminadas por otra atracción a esa otra rama / bifurcación? No estoy afirmando esto como un hecho, esto es lo que creo que puede ser cierto, estar en la misma posición que el OP y haber pasado una hora más o menos considerando mis opciones.
Myles McDonnell
44
@ Sugeriría no aceptar esta respuesta. Esto está bien para el código que aún no se ha enviado (en cuyo caso, esta es una pregunta SO más relevante, pero para el código que se comparte públicamente, haciendo un comando git que reescribe el historial (en este caso, reset --hardy un empuje forzado es muy mala práctica.) La respuesta de @errordeveloper a continuación muestra una forma de hacerlo sin necesidad de reescribir la historia o forzar la presión.
asmeurer
34

Si el tirón fue lo último que hizo, entonces

git reset --hard HEAD~1
samthebest
fuente
3
tenga cuidado al seguir estas instrucciones, en realidad me retrasó 2 pasos, no uno.
szeitlin
1
@szeitlin ¿Cómo puede suceder que te haya llevado a retroceder 2 pasos, no uno? Sé que este comentario se dejó hace más de 4 años, pero tengo curiosidad por saber si alguien sabe una respuesta sobre cómo podría suceder. Esto es muy importante para mi. Gracias.
Haradzieniec
No lo recuerdo ahora, pero supongo que podría suceder si hubiera realizado una nueva confirmación cuando intenté restablecer. Simplemente lo probaría con un repositorio ficticio si te preocupa.
szeitlin
Este me funcionó bien. Eliminó la solicitud de extracción recientemente fusionada. Después git reset --hard HEAD~1, solía git push origin -factualizar el repositorio remoto. Pero tenga cuidado, tenga cuidado antes de hacer esto.
Denis Oluka
24

A partir del 24 de junio de 2014, puede intentar cancelar un RP fácilmente (consulte " Revertir una solicitud de extracción ") con:

Presentando el botón Revertir

puede revertir fácilmente una solicitud de extracción en GitHub haciendo clic en Revertir:

https://camo.githubusercontent.com/0d3350caf2bb1cba53123ffeafc00ca702b1b164/68747470733a2f2f6769746875622d696d616765732e73332e616d617a6f6e6177732e636f6d2f68656c702f70756c6c5f72657175657374732f7265766572742d70756c6c2d726571756573742d6c696e6b2e706e67

Se le pedirá que cree una nueva solicitud de extracción con los cambios revertidos:

https://camo.githubusercontent.com/973efae3cc2764fc1353885a6a45b9a518d9b78b/68747470733a2f2f6769746875622d696d616765732e73332e616d617a6f6e6177732e636f6d2f68656c702f70756c6c5f72657175657374732f7265766572742d70756c6c2d726571756573742d6e65772d70722e706e67

Sin embargo, queda por probar si esa reversión se usa -mo no (para revertir fusiones también)

Pero Adil H Raza agrega en los comentarios (diciembre de 2019):

Ese es el comportamiento esperado, creó una nueva rama y puede crear un PR desde esta nueva rama a la suya master.
De esta manera, en el futuro, puede deshacer la reversión si es necesario, es la opción más segura y no cambia directamente su master.


Advertencia : Korayem señala en los comentarios que:

Después de una reversión, supongamos que realizó algunos cambios adicionales en la sucursal de Git y creó un nuevo RP desde la misma sucursal de origen / destino.
Encontrará que el PR muestra solo nuevos cambios, pero nada de lo que había antes de revertir .

Korayem nos remite a " Github: cambios ignorados después de revertir ( git cherry-pick, git rebase) " para obtener más información.

VonC
fuente
Intenté esto y creó una nueva rama en lugar de deshacer PR en master?
Грозный
Extraño. ¿Podría hacer una nueva pregunta para ilustrar ese comportamiento?
VonC
ese es el comportamiento esperado, creó una nueva rama y puede crear un PR desde esta nueva rama a su maestro. De esta manera, en el futuro, puede deshacer la reversión si es necesario, es la opción más segura y no cambia directamente su maestro.
Adil H. Raza
1
@ AdilH.Raza Gracias. He incluido tu comentario en la respuesta para mayor visibilidad.
VonC
1
@VonC cruzó los dedos, esto salvará a los desarrolladores de todo el mundo de demasiada agonía y pérdida de tiempo
Korayem
8

Para deshacer una solicitud de extracción de github con confirmaciones que no desea eliminar, debe ejecutar:

git reset --hard --merge <commit hash>

siendo el hash commit el commit ANTES de fusionar la solicitud de extracción. Esto eliminará todas las confirmaciones de la solicitud de extracción sin influir en ninguna confirmación dentro del historial.

Una buena manera de encontrar esto es ir a la solicitud de extracción ahora cerrada y encontrar este campo:

Imagen de solicitud de extracción Imagen de solicitud de extracción

Después de ejecutar el git reset, ejecute un:

git push origin --force <branch name>

Esto debería revertir la bifurcación antes de que la solicitud de extracción SIN afectar los commits en la rama salpicado en el historial de confirmaciones entre confirmaciones de la solicitud de extracción.

EDITAR:

Si tuviera que hacer clic en el botón de reversión en la solicitud de extracción, esto crea una confirmación adicional en la rama. NO se deshace ni se deshace. Esto significa que si presiona el botón revertir, no puede abrir una nueva solicitud de extracción para volver a agregar todo este código.

FluffySamurai
fuente
Una excelente manera de arreglar las cosas sin necesidad de una
reversión
¡Gracias! Eso era lo que estaba planeando hacer, pero eso habría sido alrededor de ~ 200 compromisos para elegir.
FluffySamurai
1

Uso este lugar todo el tiempo, gracias.

Estaba buscando cómo deshacer una solicitud de extracción y llegué aquí.

Estaba a punto de git reset --hard"hace mucho tiempo" y retrocedí rápidamente a donde estaba antes de hacer la solicitud de extracción.

Además de mirar aquí, también le pregunté a mi compañero de trabajo qué haría, y él tuvo una respuesta típicamente buena: usando el resultado de ejemplo en la primera respuesta anterior:

git reset --hard 9271e6e

Como con la mayoría de las cosas en Git, si lo estás haciendo de alguna manera que no es fácil, probablemente lo estés haciendo mal.

Mike Marshall
fuente