Rehacer una fusión revertida en Git

231

Me he encontrado con un pequeño problema aquí: tenía una rama específica del problema 28sen Git, que fusioné en la developrama general . Resulta que lo había hecho demasiado rápido, así que usé git-revert para deshacer la fusión. Ahora, sin embargo, ha llegado el momento de fusionar 28sen develop, pero comando git-merge ve la fusión original y anuncia feliz de que todo está bien y ramas ya se han fusionado. ¿Qué hago ahora? Crear un 'Revertir "Revertir" 28s -> desarrollar ""' commit? No parece ser una buena forma de hacerlo, pero no puedo imaginar ninguna otra en este momento.

Aspecto de la estructura de árbol:

Salida de registro de Git

Toms Mikoss
fuente
44
Es GitX ( gitx.frim.nl ).
Toms Mikoss

Respuestas:

169

Tienes que "revertir la reversión". Dependiendo de usted cómo se revirtió el original, puede que no sea tan fácil como parece. Mire el documento oficial sobre este tema .

---o---o---o---M---x---x---W---x---Y
              /
      ---A---B-------------------C---D

permitir:

---o---o---o---M---x---x-------x-------*
              /                       /
      ---A---B-------------------C---D

¿Pero todo funciona? Claro que si. Puede revertir una fusión, y desde un ángulo puramente técnico, git lo hizo de forma muy natural y no tuvo problemas reales.
Simplemente lo consideró un cambio de "estado antes de la fusión" a "estado después de la fusión", y eso fue todo.
Nada complicado, nada extraño, nada realmente peligroso. Git lo hará sin siquiera pensarlo.

Entonces, desde un ángulo técnico, no hay nada de malo en revertir una fusión, pero desde un ángulo de flujo de trabajo es algo que generalmente debe tratar de evitar .

Si es posible, por ejemplo, si usted encuentra un problema que quedó fusionado en el árbol principal, en lugar de revertir la fusión, tratan realmente difícil :

  • dividir el problema en la rama que fusionó y solucionarlo,
  • o intente revertir el compromiso individual que lo causó.

Sí, es más complejo, y no, no siempre va a trabajar (a veces la respuesta es: "Vaya, realmente no debería haber fusionado, porque no estaba lista todavía, y yo realmente necesita para deshacer todo de la unir"). Entonces, realmente debería revertir la fusión, pero cuando desee rehacer la fusión, ahora debe hacerlo revertiendo la reversión.

J-16 SDiZ
fuente
10
Buen enlace (+1). Me tomé la libertad de copiar parte del documento en su respuesta para permitir a los lectores ver de inmediato las opciones relevantes en este caso. Si no está de acuerdo, no dude en volver.
VonC
55
Nos encontramos con un caso en el que necesitábamos hacer esto y descubrimos que la diversión no termina aquí. Era una rama de larga duración que se fusionó, por lo que necesitábamos continuar actualizándola. Mi enfoque aquí: tech.patientslikeme.com/2010/09/29/…
jdwyah
Seguí la publicación de blog de @ jdwyah y fue glorioso (en serio, fue increíble que simplemente funcionó).
hellatan
2
@jdwyah que parece ser un enlace roto, pero parece una lectura interesante. Aquí hay un espejo de archive.org pero faltan las imágenes: web.archive.org/web/20111229193713/http://…
Alex KeySmith
15
La publicación del blog ha resucitado, gracias: blog.jdwyah.com/2015/07/dealing-with-git-merge-revisions.html
jdwyah
53

Supongamos que tienes esa historia

---o---o---o---M---W---x-------x-------*
              /                      
      ---A---B

Donde A, B falló confirmaciones y W - se revierte de M

Entonces, antes de comenzar a solucionar los problemas encontrados, hago una selección de W de mi rama

git cherry-pick -x W

Luego revierto W commit en mi rama

git revert W 

Después puedo seguir arreglando.

La historia final podría verse así:

---o---o---o---M---W---x-------x-------*
              /                       /     
      ---A---B---W---W`----------C---D

Cuando envío un RP, mostrará claramente que el RP se deshace, revierte y agrega algunas confirmaciones nuevas.

Maksim Kotlyar
fuente
3
Esto parece que puedan ser de utilidad, pero es tan escasa en los detalles (lo son C, D en el último diagrama) que es más frustrante que útil
isócrono
44
@Isochronous C y D parecen ser commits que solucionan los problemas introducidos por A y B.
Thomas
@Thomas exactamente
Maksim Kotlyar
Es bueno que haya resaltado el uso de un RP en este caso, ya que puede proporcionar una 'verificación de cordura' final antes de volver a fusionarse con el maestro.
Willem van Ketwich
use ¿por qué reinicia su rama de la W original? Es decir, deje que su tema continúe desde W, con W` seguido de C y D? Eso elimina algunas duplicaciones
Erik Carstensen
12

Para revertir la reversión sin arruinar demasiado su flujo de trabajo:

  • Crear una copia de basura local de desarrollo
  • Revertir la confirmación de reversión en la copia local de desarrollo
  • Combine esa copia en su rama de características y empuje su rama de características a su servidor git.

Su rama de características ahora debería poder fusionarse normalmente cuando esté listo para ello. El único inconveniente aquí es que tendrá algunos compromisos adicionales de fusión / reversión en su historial.

Sam Dufel
fuente
Solo para evitar más confusiones, también creé una copia 'basura' de mi rama de características y fusioné el desarrollo revertido en ella.
jhhwilliams 01 de
¡Gracias! Esta es la única respuesta que realmente explica cómo hacerlo en lugar de decir que no debe hacerlo. Realmente servicial.
Emmy
Gracias, esto realmente me ayudó. :)
Daniel Stracaboško
11

Para revertir una reversión en GIT:

git revert <commit-hash-of-previous-revert>
Ricardo
fuente
1
Usar esto en mi rama de trabajo para revertir la reversión, luego desarrollar nuevas relaciones públicas. Ahora git ve todos los cambios que estaban en el PR anterior que se revirtió. Gracias.
Danstan
3

En lugar de usar git-revert, podría haber usado este comando en la develrama para descartar (deshacer) la confirmación de fusión incorrecta (en lugar de simplemente revertirla).

git checkout devel
git reset --hard COMMIT_BEFORE_WRONG_MERGE

Esto también ajustará los contenidos del directorio de trabajo en consecuencia. Tenga cuidado :

  • Guarde sus cambios en la rama de desarrollo (desde la combinación incorrecta) porque ellos también serán borrados por el git-reset. ¡Todas las confirmaciones después de la que especifique como git resetargumento desaparecerán!
  • Además, no haga esto si sus cambios ya se extrajeron de otros repositorios porque el restablecimiento reescribirá el historial.

Recomiendo estudiar la git-resetpágina de manual cuidadosamente antes de intentar esto.

Ahora, después del reinicio, puede volver a aplicar sus cambios devely luego hacer

git checkout devel
git merge 28s

Esta será una verdadera fusión de 28sal develigual que la inicial (que ahora está borrado de la historia del GIT).

Knweiss
fuente
8
Para cualquiera que no esté súper familiarizado con git y quiera seguir estas instrucciones: cuidado con la combinación reset --hardy push origin. También tenga en cuenta que un empuje forzado al origen realmente puede acumular relaciones públicas abiertas en GitHub.
funroll
Muy útil para solucionar algunos problemas de fusión en un servidor git privado. ¡Gracias!
mix3d
1
+1 para esta técnica. Potencialmente destructivo, pero puede ahorrarle mucho dolor de cabeza (y una historia destrozada) cuando se aplica juiciosamente.
siliconrockstar
1

Acabo de encontrar esta publicación cuando enfrento el mismo problema. Me parece muy asustadizo hacer restablecimientos duros, etc. Terminaré borrando algo que no quiero y no podré recuperarlo.

En cambio, verifiqué el commit al que quería que la rama volviera, por ejemplo git checkout 123466t7632723. Luego se convirtió en una rama git checkout my-new-branch. Luego borré la rama que no quería más. Por supuesto, esto solo funcionará si eres capaz de tirar la rama que arruinaste.

Claire
fuente
1
Lo git reflogprotegerá en un restablecimiento completo durante un par de meses en caso de que luego descubra que necesita las confirmaciones perdidas. El reflog se limita a su repositorio local.
Todd
1

Le sugiero que siga los pasos a continuación para revertir una reversión, diga SHA1.

git checkout develop #go to develop branch
git pull             #get the latest from remote/develop branch
git branch users/yourname/revertOfSHA1 #having HEAD referring to develop
git checkout users/yourname/revertOfSHA1 #checkout the newly created branch
git log --oneline --graph --decorate #find the SHA of the revert in the history, say SHA1
git revert SHA1
git push --set-upstream origin users/yourname/revertOfSHA1 #push the changes to remote

Ahora cree relaciones públicas para la sucursal users/yourname/revertOfSHA1

Venkataraman R
fuente
1
  1. crear una nueva sucursal en commit antes de la fusión original - llámela 'desarrollo-base'
  2. Realice un rebase interactivo de 'desarrollo' encima de 'desarrollo-base' (aunque ya esté en la parte superior). Durante el rebase interactivo, tendrá la oportunidad de eliminar tanto el commit de fusión como el commit que invirtió la fusión, es decir, eliminar ambos eventos del historial de git

En este punto, tendrá una rama limpia de 'desarrollo' en la que puede fusionar su brach de características como lo hace regularmente.

Misha Mostov
fuente
Este enfoque creará problemas si la rama de desarrollo se comparte con otros.
PSR