what the soft index hard examples all git version-control git-reset

the - ¿Cómo puedo deshacer git reset--hard HEAD ~ 1?



reset branch git (13)

En la mayoría de los casos, sí.

Dependiendo del estado en el que se encontraba su repositorio cuando ejecutó el comando, los efectos de git reset --hard pueden ir desde triviales hasta deshacer, hasta básicamente imposibles.

A continuación, he enumerado una gama de diferentes escenarios posibles y cómo podría recuperarse de ellos.

Todos mis cambios fueron cometidos, pero ahora los compromisos se han ido!

Esta situación generalmente ocurre cuando ejecutas git reset con un argumento, como en git reset --hard HEAD~ . No te preocupes, esto es fácil de recuperar!

Si acaba de ejecutar git reset y no ha hecho nada más desde entonces, puede volver a donde estaba con esta frase única:

git reset --hard @{1}

Esto restablece su rama actual en cualquier estado en que se encontraba antes de la última vez que se modificó (en su caso, la modificación más reciente de la rama sería el restablecimiento completo que intenta deshacer).

Sin embargo, si ha realizado otras modificaciones en su sucursal desde el restablecimiento, la frase de una línea anterior no funcionará. En su lugar, debe ejecutar git reflog <branchname> para ver una lista de todos los cambios recientes realizados en su rama (incluidos los restablecimientos). Esa lista se verá algo como esto:

7c169bd master@{0}: reset: moving to HEAD~ 3ae5027 master@{1}: commit: Changed file2 7c169bd master@{2}: commit: Some change 5eb37ca master@{3}: commit (initial): Initial commit

Busque la operación en esta lista que desea "deshacer". En el ejemplo anterior, sería la primera línea, la que dice "restablecer: moviéndose a HEAD ~". Luego copie la representación de la confirmación antes (debajo) de esa operación. En nuestro caso, sería master@{1} (o 3ae5027 , ambos representan el mismo compromiso), y ejecutan git reset --hard <commit> para restablecer su rama actual de nuevo a ese commit.

Realicé mis cambios con git add , pero nunca me comprometí. ¡Ahora mis cambios se han ido!

Esto es un poco más difícil de recuperar. git tiene copias de los archivos que agregó, pero como estas copias nunca fueron vinculadas a ningún compromiso en particular, no puede restaurar los cambios todos a la vez. En su lugar, debe ubicar los archivos individuales en la base de datos de git y restaurarlos manualmente. Puedes hacerlo usando git fsck .

Para detalles sobre esto, vea Deshacer git reset - hard con archivos no confirmados en el área de preparación .

Tuve cambios en los archivos en mi directorio de trabajo que nunca monté con git add , y nunca confirmé. ¡Ahora mis cambios se han ido!

UH oh. Odio decirte esto, pero probablemente estés fuera de suerte. git no almacena los cambios que usted no agrega ni confirma, y ​​de acuerdo con la documentación para el git reset :

--difícil

Restablece el índice y el árbol de trabajo. Cualquier cambio en los archivos rastreados en el árbol de trabajo desde <commit> se descartan.

Es posible que pueda recuperar sus cambios con algún tipo de utilidad de recuperación de disco o un servicio de recuperación de datos profesional, pero en este punto es probable que haya más problemas de los que vale la pena.

¿Es posible deshacer los cambios causados ​​por el siguiente comando? ¿Si es así, cómo?

git reset --hard HEAD~1


Ejemplo de caso IRL:

$ git fsck --lost-found

Checking object directories: 100% (256/256), done. Checking objects: 100% (3/3), done. dangling blob 025cab9725ccc00fbd7202da543f556c146cb119 dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4 dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98 dangling blob 9183b84bbd292dcc238ca546dab896e073432933 dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22 dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7 dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66 dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b dangling blob b87163c8def315d40721e592f15c2192a33816bb dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7 dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133 dangling blob 4a71f9ff8262701171d42559a283c751fea6a201 dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2 dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed dangling blob 749ffc9a412e7584245af5106e78167b9480a27b dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a <- it''s this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5a Author: Stian Gudmundsen Høiland <[email protected]> Date: Wed Aug 15 08:41:30 2012 +0200 *MY COMMIT MESSAGE IS DISPLAYED HERE* diff --git a/Some.file b/Some.file new file mode 100644 index 0000000..15baeba --- /dev/null +++ b/Some.file *THE WHOLE COMMIT IS DISPLAYED HERE*

$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a

First, rewinding head to replay your work on top of it... Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.



Antes de responder, vamos a agregar algunos antecedentes, explicando qué es esta HEAD .

First of all what is HEAD?

HEAD es simplemente una referencia al compromiso actual (más reciente) en la rama actual.
Solo puede haber una sola HEAD en un momento dado. (excluyendo git worktree )

El contenido de HEAD se almacena dentro de .git/HEAD y contiene los 40 bytes SHA-1 de la confirmación actual.

detached HEAD

Si no está en la última confirmación, lo que significa que HEAD apunta a una confirmación previa en la historia, se llama detached HEAD .

En la línea de comando se verá así: SHA-1 en lugar del nombre de la rama ya que HEAD no apunta a la punta de la rama actual

Algunas opciones sobre cómo recuperarse de una CABEZA separada:

git checkout

git checkout <commit_id> git checkout -b <new branch> <commit_id> git checkout HEAD~X // x is the number of commits t go back

Esto hará que la nueva rama apunte a la confirmación deseada.
Este comando realizará el checkout a un commit dado.
En este punto, puede crear una rama y comenzar a trabajar a partir de este punto.

# Checkout a given commit. # Doing so will result in a `detached HEAD` which mean that the `HEAD` # is not pointing to the latest so you will need to checkout branch # in order to be able to update the code. git checkout <commit-id> # create a new branch forked to the given commit git checkout -b <branch name>

git reflog

Siempre puedes usar el reflog también.
git reflog mostrará cualquier cambio que actualice el HEAD y al verificar la entrada del reflog deseado, el HEAD volverá a este compromiso.

Cada vez que se modifique el HEAD habrá una nueva entrada en el reflog

git reflog git checkout HEAD@{...}

Esto te llevará de vuelta a tu compromiso deseado

git reset HEAD --hard <commit_id>

"Mueve" tu cabeza hacia atrás hasta el compromiso deseado.

# This will destroy any local modifications. # Don''t do it if you have uncommitted work you want to keep. git reset --hard 0d1d7fc32 # Alternatively, if there''s work to keep: git stash git reset --hard 0d1d7fc32 git stash pop # This saves the modifications, then reapplies that patch after resetting. # You could get merge conflicts, if you''ve modified things which were # changed since the commit you reset to.

  • Nota: ( Desde Git 2.7 )
    También puedes usar el git rebase --no-autostash también.

git revert <sha-1>

"Deshacer" el compromiso o rango dado.
El comando de reinicio "deshará" cualquier cambio realizado en el compromiso dado.
Se cometerá una nueva confirmación con el parche de deshacer, mientras que la confirmación original también se mantendrá en el historial.

# add new commit with the undo of the original one. # the <sha-1> can be any commit(s) or commit range git revert <sha-1>

Este esquema ilustra qué comando hace qué.
Como puedes ver, reset && checkout modifica la HEAD .


Es posible recuperarlo si Git aún no ha recolectado basura.

Obtenga una visión general de los compromisos colgantes con fsck :

$ git fsck --lost-found dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Recuperar el commit colgante con rebase:

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf


Hizo un pequeño script para que sea más fácil encontrar el compromiso que está buscando:

git fsck --lost-found | grep commit | cut -d '' '' -f 3 | xargs -i git show /{/} | egrep ''^commit |Date:''

Sí, se puede hacer considerablemente más bonito con awk o algo así, pero es simple y solo lo necesitaba. Podría salvar a alguien más 30 segundos.


La respuesta está oculta en la respuesta detallada de arriba, simplemente puede hacer:

$> git reset --hard HEAD@{1}

(Ver la salida de git reflog show )


Lo que desea hacer es especificar el sha1 de la confirmación que desea restaurar. Puede obtener el sha1 examinando el reflog ( git reflog ) y luego haciendo

git reset --hard <sha1 of desired commit>

Pero no espere demasiado ... después de unas pocas semanas, git finalmente verá ese commit como sin referencia y eliminará todos los blobs.


Pat Notz tiene razón. Puede recuperar el compromiso siempre que haya transcurrido unos días. git solo recolecta basura después de aproximadamente un mes, a menos que usted le indique explícitamente que elimine las manchas más nuevas.

$ git init Initialized empty Git repository in .git/ $ echo "testing reset" > file1 $ git add file1 $ git commit -m ''added file1'' Created initial commit 1a75c1d: added file1 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 file1 $ echo "added new file" > file2 $ git add file2 $ git commit -m ''added file2'' Created commit f6e5064: added file2 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 file2 $ git reset --hard HEAD^ HEAD is now at 1a75c1d... added file1 $ cat file2 cat: file2: No such file or directory $ git reflog 1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD f6e5064... HEAD@{1}: commit: added file2 $ git reset --hard f6e5064 HEAD is now at f6e5064... added file2 $ cat file2 added new file

Puede ver en el ejemplo que el archivo2 se eliminó como resultado del restablecimiento completo, pero se volvió a colocar en su lugar cuando lo reinicié por medio de la reinicialización.


Sé que este es un tema antiguo ... pero como mucha gente está buscando formas de deshacer cosas en Git, todavía creo que puede ser una buena idea continuar dando consejos aquí.

Cuando haces un "git add" o mueves algo desde la parte superior izquierda a la parte inferior izquierda en git gui, el contenido del archivo se almacena en un blob y el contenido del archivo se puede recuperar de ese blob.

Por lo tanto, es posible recuperar un archivo aunque no se haya confirmado, pero se debe haber agregado.

git init echo hello >> test.txt git add test.txt

Ahora se crea el blob pero el índice hace referencia a él, por lo que no aparecerá en la lista con git fsck hasta que lo reiniciéramos. Así que reiniciamos ...

git reset --hard git fsck

obtendrá una gota colgando ce013625030ba8dba906f756967f9e9ca394464a

git show ce01362

le devolverá el contenido del archivo "hola"

Para encontrar confirmaciones sin referencia, encontré una sugerencia en algún lugar que sugiere esto.

gitk --all $(git log -g --pretty=format:%h)

Lo tengo como herramienta en git gui y es muy útil.


Si aún no ha recolectado basura en su repositorio (p. Ej., Utilizando git repack -d o git gc , pero tenga en cuenta que la recolección de basura también puede ocurrir automáticamente), entonces su compromiso sigue ahí, simplemente ya no se puede acceder a él a través de HEAD.

Puede intentar encontrar su confirmación mirando a través de la salida de git fsck --lost-found .

Las versiones más recientes de Git tienen algo que se llama "reflog", que es un registro de todos los cambios que se realizan en las referencias (a diferencia de los cambios que se realizan en el contenido del repositorio). Así, por ejemplo, cada vez que cambies tu HEAD (es decir, cada vez que hagas un git checkout para cambiar de sucursal) eso se registrará. Y, por supuesto, tu git reset también manipuló la CABEZA, por lo que también se registró. Puede acceder a los estados más antiguos de sus referencias de una manera similar a la que puede acceder a los estados más antiguos de su repositorio, utilizando un signo @ lugar de un ~ , como git reset HEAD@{1} .

Me tomó un tiempo entender cuál es la diferencia entre HEAD @ {1} y HEAD ~ 1, así que aquí hay una pequeña explicación:

git init git commit --allow-empty -mOne git commit --allow-empty -mTwo git checkout -b anotherbranch git commit --allow-empty -mThree git checkout master # This changes the HEAD, but not the repository contents git show HEAD~1 # => One git show HEAD@{1} # => Three git reflog

Entonces, HEAD~1 significa "ir a la confirmación antes de la confirmación a la que HEAD apunta actualmente", mientras que HEAD@{1} significa "ir a la confirmación a la que HEAD apunta antes de que apunte a donde apunta actualmente".

Eso le permitirá fácilmente encontrar su compromiso perdido y recuperarlo.


Si tienes mucha suerte, como yo, puedes volver a tu editor de texto y hacer clic en "deshacer".

Sé que no es realmente una respuesta adecuada, pero me ahorró medio día de trabajo, ¡así que espero que haga lo mismo para otra persona!


que yo sepa, --hard descartará los cambios no comprometidos. Dado que estos no son rastreados por git. pero puedes deshacer el discarded commit .

$ git reflog

listas de voluntad:

b0d059c HEAD@{0}: reset: moving to HEAD~1 4bac331 HEAD@{1}: commit: added level introduction.... ....

donde 4bac331 es el discarded commit .

Ahora solo mueve la cabeza a ese cometer:

$ git reset --hard 4bac331