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.
Acabo de hacer un reinicio duro en el proyecto equivocado. Lo que me salvó la vida fue la historia local de Eclipse. Se dice que IntelliJ Idea también tiene una, y también puede valer la pena verificar su editor:
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 elgit 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