¿Cómo puedo deshacer fácilmente un git rebase?
Mis ideas actuales son solo enfoques manuales:
git checkout
en el padre de confirmación a ambas ramas- Crea una rama temporal desde allí
git cherry-pick
todos 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
--hard
opció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
(-i
no 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 --abort
oreset --hard
dependiendo 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 BACKUP
commit:
en lugar derebase:
. Suena obvio pero me confundió un poco.git reset --hard ORIG_HEAD
haría el truco tan bien inmediatamente después del rebase accidental?En realidad, rebase guarda su punto de partida, por
ORIG_HEAD
lo que esto suele ser tan simple como:Sin embargo, el
reset
,rebase
ymerge
todo Guardar el originalHEAD
puntero enORIG_HEAD
lo 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_HEAD
que ya no sea útil, también puede usar labranchName@{n}
sintaxis, donden
es la enésima posición anterior del puntero de rama. Entonces, por ejemplo, si rebase lafeatureA
rama en sumaster
rama, 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 --abort
pensamiento.git 2.17.0
.git reset --hard ORIG_HEAD
puede 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_HEAD
git 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
--onto
interruptor.Digamos que tenía una rama temática llamada imaginativamente
topic
, que se ramificómaster
cuando la punta demaster
la0deadbeef
confirmación era. En algún momento mientrastopic
estabas en la rama, lo hicistegit rebase master
. Ahora quieres deshacer esto. Así es cómo:Esto tomará todas las confirmaciones
topic
que no esténmaster
activadas y las reproducirá en la parte superior0deadbeef
.Con
--onto
, puedes reorganizar tu historia en casi cualquier forma .Que te diviertas. :-)
fuente
--onto
y-i
puedes 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ín
está la enésima posición anterior del puntero de rama. Entonces, por ejemplo, si vuelve a crear unafeatureA
rama en sumaster
rama, 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 .HEAD
de 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 --abort
da "No hay rebase en progreso"), puede restablecer fácilmente la rama usando el comando:Ejemplo:
fuente
Usar
reflog
no 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
-i
y--abort
al 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-branch
y está rastreandoorigin/your-branch
git 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-branch
git log your-branch-rebased
, comparargit log your-branch
y definir confirmaciones que faltan enyour-branch
git cherry-pick COMMIT_HASH
por cada compromiso enyour-branch-rebased
remote/your-branch
y debe presionar soloyour-branch
fuente
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ámaster
activadogit reflog master
, enumerará todos los cambios en esa rama. Se puede hacer referencia a que los cambios demaster@{1}
,master@{2}
, etc.git rebase
por 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_HEAD
no funcionará si lo usógit reset
durante un interactivorebase
.fuente
Lo que suelo hacer es
git reset #commit_hash
hasta el último commit donde creo que rebase no tuvo efecto.
entonces
git pull
Ahora 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 reflog
no 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 history
puede 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 --abort
aborta 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.