¿Cómo encuentro y restauro un archivo eliminado en un repositorio de Git?

Resuelto avdgaag asked hace 15 años • 30 respuestas

Digamos que estoy en un repositorio de Git. Elimino un archivo y confirmo ese cambio. Sigo trabajando y hago algunos compromisos más. Luego, descubro que necesito restaurar ese archivo después de eliminarlo.

Sé que puedo retirar un archivo usando git checkout <commit> -- filename.txt, pero no sé cuándo se eliminó ese archivo.

  1. ¿Cómo encuentro la confirmación que eliminó un nombre de archivo determinado?
  2. ¿Cómo restauro ese archivo en mi copia de trabajo?
avdgaag avatar Jun 05 '09 05:06 avdgaag
Aceptado

Encuentre la última confirmación que afectó la ruta dada. Como el archivo no está en la confirmación HEAD, esa confirmación anterior debe haberlo eliminado.

git rev-list -n 1 HEAD -- <file_path>

Luego, consulte la versión en la confirmación anterior, utilizando el ^símbolo de intercalación ( ):

git checkout <deleting_commit>^ -- <file_path>

O en un comando, si $filees el archivo en cuestión.

git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

Si está utilizando zsh y tiene habilitada la opción EXTENDED_GLOB, el símbolo de intercalación no funcionará. Puedes usar ~1en su lugar.

git checkout $(git rev-list -n 1 HEAD -- "$file")~1 -- "$file"
CB Bailey avatar Jul 11 '2009 07:07 CB Bailey
  1. Obtenga todas las confirmaciones que han eliminado archivos, así como los archivos que se eliminaron:

    git log --diff-filter=D --summary
    

    Tome nota del hash de confirmación deseado, por ejemplo e4e6d4d5e5c59c69f3bd7be2.

  2. Restaure el archivo eliminado de una confirmación anterior ( ~1) a la confirmación determinada anteriormente ( e4e6d4d5e5c59c69f3bd7be2):

    git checkout e4e6d4d5e5c59c69f3bd7be2~1 path/to/file.ext
    

    Nota la ~1. La especificación de tilde le dará el enésimo abuelo de la confirmación nombrada.

Robert Munteanu avatar Jun 04 '2009 23:06 Robert Munteanu

Para restaurar todos los archivos eliminados en una carpeta:

git ls-files -d | xargs git checkout --
Manu avatar Dec 02 '2010 06:12 Manu

Si eliminó un archivo que existe en la última HEADconfirmación, puede restaurarlo usando:

git checkout HEAD -- path/to/file.ext
Brett avatar Apr 10 '2014 00:04 Brett

Si estás loco, usa git-bisect. Esto es lo que debe hacer:

git bisect start
git bisect bad
git bisect good <some commit where you know the file existed>

Ahora es el momento de ejecutar la prueba automatizada. El comando de shell '[ -e foo.bar ]'devolverá 0 si foo.barexiste y 1 en caso contrario. El comando "ejecutar" git-bisectutilizará la búsqueda binaria para encontrar automáticamente la primera confirmación donde falla la prueba. Comienza a la mitad del rango dado (de bueno a malo) y lo corta a la mitad según el resultado de la prueba especificada.

git bisect run '[ -e foo.bar ]'

Ahora estás en la confirmación que lo eliminó. Desde aquí, puede retroceder al futuro y utilizar git-revertpara deshacer el cambio.

git bisect reset
git revert <the offending commit>

o puedes retroceder una confirmación e inspeccionar manualmente el daño:

git checkout HEAD^
cp foo.bar /tmp
git bisect reset
cp /tmp/foo.bar .
Josh Lee avatar Jun 04 '2009 22:06 Josh Lee

Mi nuevo alias favorito, basado en la respuesta de bonyiii (votada a favor) y mi propia respuesta sobre " Pasar un argumento a un comando de alias de Git ":

git config alias.restore '!f() { git checkout $(git rev-list -n 1 HEAD -- $1)~1 -- $(git diff --name-status $(git rev-list -n 1 HEAD -- $1)~1 | grep '^D' | cut -f 2); }; f'

¿Perdí un archivo, lo eliminé por error hace algunas confirmaciones?
Rápido:

git restore my_deleted_file

Crisis evitada.

Advertencia, con Git 2.23 (tercer trimestre de 2019) viene el comando experimental llamado git restore(!).
Así que cambie el nombre de este alias (como se muestra a continuación).


Robert Dailey propone en los comentarios el siguiente alias:

restore-file = !git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "$1"

Y jegan agrega en los comentarios :

Para configurar el alias desde la línea de comando, utilicé este comando:

git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\"" 
VonC avatar Feb 17 '2013 15:02 VonC