Pregunta

¿Alguien sabe cómo deshacer fácilmente una rebase de git?

La única forma que se me ocurre es hacerlo manualmente:

  • git checkout el padre de compromiso para ambas ramas
  • luego crea una rama temporal desde allí
  • seleccione todas las confirmaciones a mano
  • reemplazar la rama en la que volví a basar por la rama creada manualmente

En mi situación actual, esto funcionará porque puedo detectar fácilmente las confirmaciones de ambas ramas (una era mía, la otra era de mi colega).

Sin embargo, mi enfoque me parece subóptimo y propenso a errores (digamos que acababa de cambiar la base con 2 de mis propias ramas).

¿Algunas ideas?

Aclaración:Estoy hablando de una rebase durante la cual se repitieron un montón de confirmaciones.No solo uno.

¿Fue útil?

Solución

La forma más fácil sería encontrar el commit principal de la rama tal como estaba inmediatamente antes de que comenzara el rebase en reflog ...

git reflog

y para restablecer la rama actual (con las advertencias habituales sobre estar absolutamente seguro antes de restablecer con la opción --hard).

Suponga que la confirmación anterior estaba HEAD@{5} en el registro de referencia:

git reset --hard HEAD@{5}

En Windows, puede que necesite citar la referencia:

git reset --hard "HEAD@{5}"

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 simplemente hacer git reflog branchname@{1} como una nueva separación separa la cabeza de la rama antes de volver a colocarla en la cabeza final. Verificaría esto dos veces, aunque no lo he verificado recientemente.

Por defecto, todos los reflogs se activan para repositorios no descubiertos:

[core]
    logAllRefUpdates = true

Otros consejos

En realidad, rebase guarda su punto de partida en ORIG_HEAD entonces esto suele ser tan simple como:

git reset --hard ORIG_HEAD

sin embargo, el reset, rebase y merge todos guardan su original HEAD puntero hacia ORIG_HEAD entonces, si ha ejecutado alguno de esos comandos desde el cambio de base que está intentando deshacer, tendrá que usar reflog.

La respuesta de Charles funciona, pero es posible que desee hacer esto:

git rebase --abort

para limpiar después del reset.

De lo contrario, puede recibir el mensaje & # 8220; Interactive rebase already started & # 8221 ;.

git reflog le mostrará todos los cambios antes y después del rebase, y le permitirá encontrar el correcto para restablecer. Pero me sorprende que nadie haya mencionado esta otra forma súper simple aquí todavía:

Rebase deja el estado anterior como ORIG_HEAD, para que pueda revertir el último rebase ejecutando:

git reset --hard ORIG_HEAD

Restablecer la rama al objeto de confirmación pendiente de su antiguo tip es, por supuesto, la mejor solución, porque restaura el estado anterior sin gastar ningún esfuerzo.Pero si ha perdido esas confirmaciones (p.ej.Debido a que mientras tanto recogiste basura en tu repositorio, o este es un clon nuevo), siempre puedes cambiar la base de la rama nuevamente.La clave para esto es la --onto cambiar.

Digamos que tienes una rama temática llamada imaginativamente topic, que te bifurcaste master cuando la punta de master fue el 0deadbeef comprometerse.En algún momento mientras estaba en el topic rama, lo hiciste git rebase master.Ahora quieres deshacer esto.Así es cómo:

git rebase --onto 0deadbeef master topic

Esto requerirá todos los compromisos topic que no estan encendidos master y reproducirlos encima de 0deadbeef.

Con --onto, puedes reorganizar tu historial en prácticamente cualquier forma.

Divertirse.:-)

De hecho, puse una etiqueta de respaldo en la rama antes de hacer una operación no trivial (la mayoría de las rebase son triviales, pero lo haría si se ve en algún lugar complejo).

Luego, la restauración es tan fácil como git reset --hard BACKUP.

En caso de que haya empujado su sucursal al repositorio remoto (generalmente es el origen) y luego haya realizado un rebase exitoso (sin fusión) (git rebase --abort da " Sin rebase en progreso ") puede fácilmente restablecer rama usando comando:

  

git reset --hard source / {branchName}

Ejemplo:

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'origin/{branchName}' by 135 commits.
  (use "git push" to publish your local commits)

nothing to commit, working directory clean

$ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
HEAD is now at 6df5719 "Commit message".

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'origin/{branchName}.

nothing to commit, working directory clean

En caso de que no haya completado el rebase y en medio de él, lo siguiente funciona:

git rebase --abort

Usar reflog no funcionó para mí.

Lo que funcionó para mí fue similar a lo descrito aquí . Abra el archivo en .git / logs / refs con el nombre de la rama que se ha modificado y encuentre la línea que contiene & Quot; rebase finsihed & Quot ;, algo así como:

5fce6b51 88552c8f Kris Leech <me@example.com> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878

Revisa el segundo commit listado en la línea.

git checkout 88552c8f

Una vez confirmado que contenía mis cambios perdidos, me bifurqué y solté un suspiro de alivio.

git log
git checkout -b lost_changes

Para las confirmaciones múltiples, recuerde que cualquier confirmación hace referencia a todo el historial previo a esa confirmación. Entonces, en la respuesta de Charles, lea & Quot; el antiguo commit & Quot; 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.

Siguiendo la solución de @Allan y @Zearin, me gustaría poder simplemente hacer un comentario, pero no tengo suficiente reputación, así que utilicé el siguiente comando:

en lugar de hacer git rebase -i --abort (nota la -i) Tuve que simplemente hacer git rebase --abort (sin el -i).

Usando ambos -i y --abort al mismo tiempo hace que Git me muestre una lista de uso/opciones.

Entonces, el estado de mi sucursal anterior y actual con esta solución es:

matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort

matbhz@myPc /my/project/environment (branch-123)
$

Si rebasó exitosamente la sucursal remota y no puede git rebase --abort Aún puedes hacer algunos trucos para guardar tu trabajo y no tener que forzarlo.Supongamos que su rama actual que fue rebasada por error se llama your-branch y está rastreando origin/your-branch

  • git branch -m your-branch-rebased # cambiar el nombre de la rama actual
  • git checkout origin/your-branch # pago al último estado conocido por el origen
  • git checkout -b your-branch
  • controlar git log your-branch-rebased, comparar con git log your-branch y definir confirmaciones que faltan en your-branch
  • git cherry-pick COMMIT_HASH por cada compromiso en your-branch-rebased
  • impulsar sus cambios.Tenga en cuenta que dos sucursales locales están asociadas con remote/your-branch y solo debes empujar your-branch

Digamos que reescribo el master a mi rama de características y obtengo 30 confirmaciones nuevas que rompen algo. He descubierto que a menudo es más fácil eliminar las confirmaciones incorrectas.

git rebase -i HEAD~31

Reorganización interactiva para las últimas 31 confirmaciones (no hace daño si elige demasiadas).

Simplemente tome los commits de los que desea deshacerse y márquelos con " d " en lugar de " seleccione " ;. Ahora, los commits se eliminan efectivamente deshaciendo el rebase (si elimina solo los commits que acaba de obtener al rebase).

Si está en una sucursal, puede usar:

git reset --hard @{1}

No solo hay un registro de referencia para HEAD (obtenido por git reflog), también hay reflogs para cada rama (obtenida por git reflog <branch>). Entonces, si está en master entonces git reflog master enumerará todos los cambios en esa rama. Puede referirse a esos cambios por master@{1}, master@{2}, etc.

git rebase generalmente cambiará HEAD varias veces, pero la rama actual se actualizará solo una vez.

@{1} es simplemente un acceso directo para la rama actual , entonces es igual a git reset --hard ORIG_HEAD si está en git reset.

rebase no funcionará si usó <=> durante un <=> interactivo.

Para los novatos / cualquiera que esté demasiado asustado de hacer un restablecimiento completo, puede verificar el commit desde el registro y luego guardarlo como una nueva rama.

git reflog

Encuentre la confirmación justo antes de comenzar a cambiar el nombre. Es posible que deba desplazarse más hacia abajo para encontrarlo (presione Entrar o PageDown). Tome nota del número HEAD y reemplace 57:

git checkout HEAD@{57}

Revise la rama / commits, si se ve bien, cree una nueva rama usando este HEAD:

git checkout -b new_branch_name

git reset --hard source / {branchName}

es la solución correcta para restablecer todos los cambios locales realizados por rebase.

Lo que suelo hacer es git reset #commit_hash

a la última confirmación donde creo que rebase no tuvo efecto.

luego git pull

Ahora su rama debería coincidir exactamente como las confirmaciones master y rebase no deberían estar en ella.

Ahora uno puede simplemente seleccionar los commits en esta rama.

Si arruinas algo dentro de una rebase de git, p. git rebase --abort, mientras tenga archivos no confirmados, se perderán y git reflog no ayudará.Esto me pasó a mí y tendrás que pensar fuera de lo común aquí.Si tienes suerte como yo y usas IntelliJ Webstorm, entonces puedes right-click->local history y puede volver a un 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 sistema de seguridad en ejecución.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top