¿Cómo puedo deshacer fácilmente un git rebase?
Mis ideas actuales son solo enfoques manuales:
git checkouten el padre de confirmación a ambas ramas- Crea una rama temporal desde allí
git cherry-picktodos los commits a mano- reemplace la rama en la que rebase por la rama creada manualmente
En mi situación actual, esto funcionaría porque puedo detectar fácilmente las confirmaciones de ambas ramas (una era lo mío, la otra era lo de mi colega).
Sin embargo, mi enfoque me parece subóptimo y propenso a errores (digamos que acababa de cambiar el nombre con 2 de mis propias ramas).
Aclaración : estoy hablando de un rebase durante el cual se repitieron varios commits. No solo uno.
git
rebase
git-rebase
undo
webmat
fuente
fuente

Respuestas:
La forma más fácil sería encontrar el commit principal de la sucursal tal como estaba inmediatamente antes de que comenzara el rebase en el registro ...
y para restablecer la rama actual (con las advertencias habituales sobre estar absolutamente seguro antes de restablecer con la
--hardopción).Supongamos que la confirmación anterior estaba
HEAD@{5}en el registro de referencia:En Windows, puede que necesite citar la referencia:
Puede verificar el historial del antiguo jefe candidato simplemente haciendo un
git log HEAD@{5}( Windows:)git log "HEAD@{5}".Si no ha deshabilitado los registros de registros por rama, debería poder hacerlo simplemente ya
git reflog branchname@{1}que un rebase separa la cabeza de la rama antes de volver a unirla a la cabeza final. Verificaría esto dos veces, aunque no lo he verificado recientemente.Por defecto, todos los reflogs se activan para repositorios no desnudos:
fuente
git log -g(consejo de progit.org/book de Scott Chacon ).git rebase --abort(-ino tiene sentido--abort) es por abandonar un rebase que no se ha completado, ya sea porque hubo conflictos o porque fue interactivo o ambos; no se trata de deshacer un rebase exitoso, de eso se trata la pregunta. Usted usaríarebase --abortoreset --harddependiendo de la situación en la que se encuentre. No debería necesitar hacer ambas cosas.git tag BACKUP. Puede regresar si algo sale mal:git reset --hard BACKUPcommit:en lugar derebase:. Suena obvio pero me confundió un poco.git reset --hard ORIG_HEADharía el truco tan bien inmediatamente después del rebase accidental?En realidad, rebase guarda su punto de partida, por
ORIG_HEADlo que esto suele ser tan simple como:Sin embargo, el
reset,rebaseymergetodo Guardar el originalHEADpuntero enORIG_HEADlo que, si usted ha hecho alguna de esas órdenes ya que el rebase que está tratando de deshacer entonces usted tendrá que usar la reflog.fuente
ORIG_HEADque ya no sea útil, también puede usar labranchName@{n}sintaxis, dondenes la enésima posición anterior del puntero de rama. Entonces, por ejemplo, si rebase lafeatureArama en sumasterrama, pero no le gusta el resultado de la rebase, entonces simplemente puede hacergit reset --hard featureA@{1}para restablecer la rama exactamente donde estaba antes de hacer la rebase. Puede leer más sobre la sintaxis de branch @ {n} en los documentos oficiales de Git para revisiones .git rebase --abortpensamiento.git 2.17.0.git reset --hard ORIG_HEADpuede usarlo repetidamente para retroceder una y otra vez. Digamos, si A --- rebase a --- B --- rebase a --- C, ahora estoy en C, puedo volver a A usando dos vecesgit reset --hard ORIG_HEADgit rebase --abort?La respuesta de Charles funciona, pero es posible que desee hacer esto:
para limpiar después de la
reset.De lo contrario, puede recibir el mensaje "
Interactive rebase already started".fuente
Restablecer la rama al objeto de confirmación colgante de su punta anterior es, por supuesto, la mejor solución, porque restaura el estado anterior sin gastar ningún esfuerzo. Pero si por casualidad ha perdido esas confirmaciones (por ejemplo, porque recolectó basura su repositorio mientras tanto, o este es un clon nuevo), siempre puede volver a cambiar la rama. La clave para esto es el
--ontointerruptor.Digamos que tenía una rama temática llamada imaginativamente
topic, que se ramificómastercuando la punta demasterla0deadbeefconfirmación era. En algún momento mientrastopicestabas en la rama, lo hicistegit rebase master. Ahora quieres deshacer esto. Así es cómo:Esto tomará todas las confirmaciones
topicque no esténmasteractivadas y las reproducirá en la parte superior0deadbeef.Con
--onto, puedes reorganizar tu historia en casi cualquier forma .Que te diviertas. :-)
fuente
--ontoy-ipuedes reorganizar tu historia en casi cualquier forma. Usa gitk (o gitx en mac) para ver las formas que haces :-).De hecho, puse una etiqueta de copia de seguridad en la rama antes de hacer cualquier operación no trivial (la mayoría de las rebase son triviales, pero lo haría si se ve en algún lugar complejo).
Entonces, restaurar es tan fácil como
git reset --hard BACKUP.fuente
branchName@{n}sintaxis, aquínestá la enésima posición anterior del puntero de rama. Entonces, por ejemplo, si vuelve a crear unafeatureArama en sumasterrama, pero no le gusta el resultado de la modificación, entonces simplemente puede hacergit reset --hard featureA@{1}para restablecer la rama exactamente donde estaba antes de hacer la modificación. Puede leer más sobre labranch@{n}sintaxis en los documentos oficiales de Git para revisiones .HEADde la rama se almacena temporalmente enORIG_HEAD. Pero la técnica de usar una etiqueta de rama de respaldo también funciona, son solo más pasos.En caso de que haya empujado su bifurcación al repositorio remoto (generalmente es el origen) y luego haya realizado un cambio de base exitoso (sin fusión) (
git rebase --abortda "No hay rebase en progreso"), puede restablecer fácilmente la rama usando el comando:Ejemplo:
fuente
Usar
reflogno funcionó para mí.Lo que funcionó para mí fue similar a lo que se describe aquí . Abra el archivo en .git / logs / refs con el nombre de la rama que se ha modificado y busque la línea que contiene "rebase finsihed", algo así como:
Verifique el segundo commit listado en la línea.
Una vez confirmado que contenía mis cambios perdidos, me bifurqué y solté un suspiro de alivio.
fuente
Para las confirmaciones múltiples, recuerde que cualquier confirmación hace referencia a toda la historia previa a esa confirmación. Entonces, en la respuesta de Charles, lea "el viejo commit" como "el más nuevo de los viejos commits". Si restablece esa confirmación, volverá a aparecer todo el historial previo a esa confirmación. Esto debería hacer lo que quieras.
fuente
Siguiendo la solución de @Allan y @Zearin, desearía poder simplemente hacer un comentario, pero no tengo suficiente reputación, así que he usado el siguiente comando:
En lugar de hacerlo
git rebase -i --abort(tenga en cuenta el -i ) tuve que hacer simplementegit rebase --abort( sin el -i ).Usar ambos
-iy--abortal mismo tiempo hace que Git me muestre una lista de uso / opciones.Entonces, mi estado de sucursal anterior y actual con esta solución es:
fuente
Si reescribió con éxito contra una rama remota y no puede
git rebase --abort, aún puede hacer algunos trucos para salvar su trabajo y no tener empujes forzados. Supongamos que se llama a su rama actual que se modificó por erroryour-branchy está rastreandoorigin/your-branchgit branch -m your-branch-rebased# cambiar el nombre de la rama actualgit checkout origin/your-branch# checkout al último estado que se conoce como origengit checkout -b your-branchgit log your-branch-rebased, comparargit log your-branchy definir confirmaciones que faltan enyour-branchgit cherry-pick COMMIT_HASHpor cada compromiso enyour-branch-rebasedremote/your-branchy debe presionar soloyour-branchfuente
Digamos que rebase master a mi rama de características y obtengo 30 nuevos commits que rompen algo. He descubierto que a menudo es más fácil eliminar las confirmaciones incorrectas.
Reorganización interactiva para los últimos 31 commits (no hace daño si elige demasiados).
Simplemente tome los commits de los que desea deshacerse y márquelos con "d" en lugar de "pick". Ahora los commits se eliminan efectivamente deshaciendo el rebase (si elimina solo los commits que acaba de obtener al rebase).
fuente
Para los novatos / alguien demasiado asustado de hacer un restablecimiento completo, puede verificar el compromiso desde el registro y luego guardarlo como una nueva rama.
Encuentra el commit justo antes de comenzar a rebasar. Es posible que deba desplazarse más hacia abajo para encontrarlo (presione Entrar o PageDown). Tome nota del número de HEAD y reemplace 57:
Revise la rama / commits, si se ve bien, cree una nueva rama usando este HEAD:
fuente
Si estás en una sucursal puedes usar:
No solo hay un registro de referencia para HEAD (obtenido por
git reflog), también hay reflogs para cada rama (obtenida porgit reflog <branch>). Entonces, si estámasteractivadogit reflog master, enumerará todos los cambios en esa rama. Se puede hacer referencia a que los cambios demaster@{1},master@{2}, etc.git rebasepor lo general, cambiará HEAD varias veces, pero la rama actual se actualizará solo una vez.@{1}es simplemente un acceso directo para la rama actual , por lo que es igual amaster@{1}si está activadomaster.git reset --hard ORIG_HEADno funcionará si lo usógit resetdurante un interactivorebase.fuente
Lo que suelo hacer es
git reset #commit_hashhasta el último commit donde creo que rebase no tuvo efecto.
entonces
git pullAhora su rama debe coincidir exactamente como las confirmaciones maestra y con rebase no deben estar en ella.
Ahora uno solo puede elegir los commits en esta rama.
fuente
Intenté todas las sugerencias con restablecer y volver a registrar sin ningún éxito. Restaurar el historial local de IntelliJ resolvió el problema de los archivos perdidos
fuente
git reset --hard source / {branchName}
es la solución correcta para restablecer todos los cambios locales realizados por rebase.
fuente
origin/branch, puede perder los cambios entre HEAD y ese punto. No quieres eso en general.Si desordena algo dentro de un rebase git, por ejemplo
git rebase --abort, mientras tiene archivos no confirmados, se perderán ygit reflogno ayudarán. Esto me sucedió y tendrás que pensar fuera de la caja aquí. Si tiene suerte como yo y utiliza IntelliJ Webstorm,right-click->local historypuede volver al estado anterior de sus archivos / carpetas sin importar los errores que haya cometido con el software de control de versiones. Siempre es bueno tener otro funcionamiento a prueba de fallos.fuente
git rebase --abortaborta un rebase activo, no deshace un rebase. Además, usar dos VCS al mismo tiempo es una mala idea. Es una buena característica en el software Jetbrains, pero no debe usar ambos. Es mejor aprender Git, especialmente al responder preguntas sobre Stack Overflow que tratan sobre Git.