Recuperar files que se agregaron al índice pero luego se eliminaron mediante un reinicio de git

git reset --hard algunos files al índice pero luego los borré por error con el git reset --hard . ¿Cómo los recupero? Esto es lo que sucedió:

  1. Agregué todos los files usando git add .
  2. Entonces me comprometí
  3. Cuando revisé el estado, aún había files que no estaban incluidos en la confirmación del complemento, lo cual era extraño
  4. Agregué los files sin seguimiento otra vez y funcionó esta vez
  5. Pero quería que todo estuviera en una sola confirmación, así que busqué la manera de desestabilizar lo que acabo de comprometer
  6. Utilicé git reset --hard HEAD^ – mala idea, obviamente, todos los files fueron eliminados
  7. entonces usé git reflog para encontrar donde lo dejé
  8. luego utilicé git reflog ______ para volver a mi último compromiso.
  9. luego utilicé git reset HEAD para desempatar la confirmación (lo que debería haber hecho originalmente) pero los files que agregué (ver arriba) después de la confirmación aún se habían ido.

¿Cómo recupero esos files?

Primero, haz una copy de security completa de tu repository de Git.

Cuando git add un file, git creará un blob del contenido de este file y lo agregará a su database de objects ( .git/objects/??/* ).

Miremos sus commands, uno por uno:

Agregué todos los files usando git add.

 $ git add . 

Esto agregará todos los files contenidos en el directory actual y sus subdirectorys a la database de objects de Git. Los files sin seguimiento que coinciden con los patrones de los files .gitignore no se agregarán. Los files de tree también se escribirán. Por favor, mira el final de mi respuesta.

Entonces me comprometí

 $ git commit -m'added all files' 

Esto escribirá un nuevo object de confirmación en la database de objects. Este compromiso hará reference a un solo tree. El tree hace reference a blobs (files) y otros treees (subdirectorys).

Cuando revisé el estado, aún había files que no estaban incluidos en la confirmación del complemento, lo cual era extraño

 $ git status 

Puedo pensar en dos escenarios donde sucede esto: algo modificó sus files o se agregaron nuevos files a sus espaldas.

Agregué los files sin seguimiento otra vez y funcionó esta vez

 $ git add . 

Supongo que usaste el mismo command add nuevamente, como en el paso 1.

Pero quería que todo estuviera en una sola confirmación, así que busqué la manera de desestabilizar lo que acabo de comprometer

Te diré una forma mejor al final de esta respuesta, que no requiere que el usuario emita un reset potencialmente peligroso

Utilicé git reset –hard HEAD ^ – mala idea, obviamente, todos los files fueron eliminados

 $ git reset --hard HEAD^ 

Este command configurará el tree y el índice de trabajo actuales para que estén exactamente en la HEAD^ confirmación HEAD^ (la penúltima confirmación). En otras palabras, descartará cualquier cambio local no confirmado y moverá el puntero de bifurcación hacia atrás una confirmación. No toca files sin seguimiento.

entonces usé git reflog para encontrar donde lo dejé

 $ git reflog 

Esto muestra los últimos commits que fueron revisados ​​recientemente (idéntico a git reflog HEAD ). Si especifica un nombre de twig, le mostrará los últimos commits a los que esta twig señaló recientemente.

luego utilicé git reflog __ para volver a mi último compromiso.

No estoy seguro de este. git reflog es (principalmente) un command de solo lectura y no se puede usar para "volver" a commits. Solo puedes usarlo, para encontrar commits apunta a una twig (o HEAD ).

luego utilicé git reset HEAD para desempatar la confirmación (lo que debería haber hecho originalmente) pero los files que agregué (ver arriba) después de la confirmación aún se habían ido. $ git reset HEAD

Esto no desestabilizará este compromiso, pero desestabilizará todos los cambios por etapas (pero no confirmados) del índice. Originalmente (primer paso), querías decir que git reset HEAD^ (o git reset --mixed HEAD^ ) – esto dejará intacto tu tree de trabajo, pero establece el índice para que coincida con el tree al que apunta el commit nombrado por HEAD^ .


Ahora, para recuperar sus files, debe usar git fsck --full --unreachable --no-reflog . Escaneará todos los objects en la database de objects de Git y realizará un análisis de accesibilidad. Desea search objects blob . También debe haber un object de tree que describa el estado después de su segundo git add .

git cat-file -p <object hash> imprimirá el contenido de los files, para que pueda verificar que tiene los objects correctos. Para blobs, puede usar la networkingirección de IO para escribir el contenido en el nombre de file correcto. Para treees, tienes que usar commands git read-tree ( git read-tree ). Si solo se trata de unos pocos files, es mejor que los escriba directamente en los files.


Algunas notas aquí:

Si desea agregar files al último commit (o editar su post de confirmación), simplemente puede usar git commit --amend . Básicamente se trata de un git reset --soft HEAD^ && git commit -c [email protected]{1} .

Además, casi nunca es una buena idea usar git add . . Por lo general, solo desea usarlo la primera vez, cuando está creando un nuevo repository. Las mejores alternativas son git add -u , git commit -a , que representará todos los cambios en los files rastreados. Para rastrear nuevos files, mejor especifíquelos explícitamente.

Tuve un problema similar, pero tenía muchos blobs y treees colgando en mi repository, así que terminé filtrando con grep la salida de todos los blobs colgantes e imprimí los que coincidían. Suponiendo que ${UNIQUE_CODE} es un código exclusivo de los files que tenía en el índice, esto debería proporcionarle los valores hash de los blobs que está buscando:

 for b in $(git fsck --lost-found | grep blob | awk '{print $3}'); do git cat-file -p $b | grep -q ${UNIQUE_CODE} && echo $b; done