¿Cómo encuentro y restauro un archivo eliminado en un repositorio de Git?
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.
- ¿Cómo encuentro la confirmación que eliminó un nombre de archivo determinado?
- ¿Cómo restauro ese archivo en mi copia de trabajo?
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 $file
es 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 ~1
en su lugar.
git checkout $(git rev-list -n 1 HEAD -- "$file")~1 -- "$file"
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
.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.
Para restaurar todos los archivos eliminados en una carpeta:
git ls-files -d | xargs git checkout --
Si eliminó un archivo que existe en la última HEAD
confirmación, puede restaurarlo usando:
git checkout HEAD -- path/to/file.ext
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.bar
existe y 1 en caso contrario. El comando "ejecutar" git-bisect
utilizará 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-revert
para 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 .
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\""