¿Cómo encontrar un archivo eliminado en el historial de confirmación del proyecto?

1275

Érase una vez, había un archivo en mi proyecto que ahora me gustaría poder obtener.

El problema es: no tengo idea de cuándo lo eliminé y en qué ruta estaba.

¿Cómo puedo localizar las confirmaciones de este archivo cuando existía?

Pedro Rolo
fuente
Pregunta similar aquí: stackoverflow.com/questions/7093602/…
eckes
3
Posible duplicado de Buscar cuando se eliminó un archivo en Git
Dan Dascalescu
13
Las respuestas aquí son más útiles para mí que las respuestas en los duplicados .
Felipe Alvarez
55
de acuerdo ... independientemente de los duplicados ... no aparecieron en la búsqueda de Google ... este sí ... espero que dejemos de perder el tiempo persiguiendo los duplicados ... solo el tiempo y el algoritmo de Google diga qué pregunta es la mejor.
Tim Boland

Respuestas:

1601

Si no conoce la ruta exacta que puede usar

git log --all --full-history -- "**/thefile.*"

Si conoce la ruta en la que se encontraba el archivo, puede hacer esto:

git log --all --full-history -- <path-to-file>

Esto debería mostrar una lista de confirmaciones en todas las ramas que tocaron ese archivo. Luego, puede encontrar la versión del archivo que desea y mostrarla con ...

git show <SHA> -- <path-to-file>

O restaurarlo en su copia de trabajo con:

git checkout <SHA>^ -- <path-to-file>

Tenga en cuenta el símbolo de intercalación ( ^), que obtiene el pago antes del identificado, porque en el momento de <SHA>confirmar el archivo se elimina, debemos mirar el compromiso anterior para obtener el contenido del archivo eliminado

Ámbar
fuente
2
Intente usar una ruta relativa en lugar de una ruta absoluta (si aún no lo ha hecho).
Ámbar
63
¿Qué pasa si no sabes el camino exacto? Todo lo que sabes es el nombre del archivo?
priestc
17
@PedroMorteRolo git log -- <path>no tendrá salida cuando se encuentre en una rama en la que el archivo nunca existió. Siempre debe usar git log --all -- <path>, para asegurarse de no perderse los cambios que ocurrieron en otras ramas. El comando git log -- <path>puede ser muy peligroso si tiene más de una rama y tiende a olvidar rutas y ramas (como yo) y también es peligroso si trabaja con otros desarrolladores.
placas
44
@Amber, considera agregar --all(gracias Philip ) a tu git logrespuesta, para que las personas no se pierdan los cambios y los archivos en otras ramas. Ahorraría mucho dolor a las personas olvidadizas como yo.
placas
3
Como se indica en la respuesta a continuación, la restauración del archivo debe ser git checkout <SHA>^ -- <path-to-file>(tenga en cuenta el símbolo ^), porque en el momento de <SHA> confirmar el archivo se elimina, tenemos que mirar la confirmación anterior para obtener el contenido del archivo eliminado
kipelovets
393

Obtenga una lista de los archivos eliminados y copie la ruta completa del archivo eliminado

git log --diff-filter=D --summary | grep delete

Ejecute el siguiente comando para encontrar la identificación de confirmación de esa confirmación y copie la identificación de confirmación

git log --all -- FILEPATH

Mostrar diferencias del archivo eliminado

git show COMMIT_ID -- FILE_PATH

Recuerde, puede escribir la salida en un archivo usando >like

git show COMMIT_ID -- FILE_PATH > deleted.diff
Fatih Acet
fuente
1
Aunque he encontrado el camino con ayuda del primer paso, el segundo paso lanza este error: unknown revision or path not in the working tree.
jvannistelrooy
66
Para ver los hashes de confirmación junto con las eliminaciones, puede hacerlogit log --diff-filter=D --summary | grep -E 'delete|^commit\s+\S+'
Chris Middleton,
1
El paso 2 no devuelve nada. ¿Alguna idea de por qué puede suceder? Mi nombre de archivo es correcto.
Denis Kniazhev
2
Para encontrar la combinación de las tres en una función, agregue esto a su .bashrc o .zshrc: git-grep-latest(){ result_path=$(git log --diff-filter=D --summary | grep $1 | head -1 | awk '{print $4;}'); latest_commit=$(git log --all -- $result_path | head -1 | awk '{print $2;}'); git show $latest_commit -- $result_path; }y ahora solo puede hacer:git-grep-latest some_text
randomor
1
@ TylerJones puedes alimentar cualquier cosa con linux usando tuberías - google linux pipes... te gustará eso.
John Hunt
37

No se pudo editar la respuesta aceptada, por lo que se agrega aquí como respuesta,

para restaurar el archivo en git, use lo siguiente (observe el signo '^' justo después del SHA)

git checkout <SHA>^ -- /path/to/file
Akshay Agarwal
fuente
No entiendo por qué quieres la ^. El archivo está EN el commit con ese SHA ... ¿por qué querrías retroceder otro commit desde allí?
Tony K.
19
Está en el commit con ese sha como "eliminado", lo que significa que todavía no existirá. Tienes que ir al commit antes de eso para recuperarlo.
tandrewnichols
66
@tandrewnichols, lo que significa que está utilizando el SHA de confirmación incorrecto: desea la confirmación de la versión del archivo que desea ... que probablemente no sea la versión donde se elimina el archivo.
Ámbar
66
@Amber y la confirmación que desea es probablemente la más reciente antes de que se elimine, de ahí esta respuesta.
Sam Holder
1
@AlexR: <SHA>~1debería funcionar igual sin la necesidad de envolverlo con comillas.
CodeManX
37

Supongamos que desea recuperar un archivo llamado MyFile, pero no está seguro de su ruta (o su extensión, para el caso):

Prelim .: evite la confusión dando un paso hacia la raíz git

Un proyecto no trivial puede tener múltiples directorios con nombres similares o idénticos.

> cd <project-root>
  1. Encuentra el camino completo

    git log --diff-filter = D --summary | grep eliminar | grep MyFile

    delete mode 100644 full/path/to/MyFile.js

full/path/to/MyFile.js es la ruta y el archivo que estás buscando.

  1. Determinar todas las confirmaciones que afectaron ese archivo

    git log --oneline --follow - full / path / to / MyFile.js

    bd8374c Some helpful commit message

    ba8d20e Another prior commit message affecting that file

    cfea812 The first message for a commit in which that file appeared.

  2. Retirar el archivo

Si elige el primer commit listado (el último cronológicamente, aquí bd8374c), el archivo no se encontrará, ya que se eliminó en ese commit.

> git checkout bd8374c -- full/path/to/MyFile.js

`error: pathspec 'full/path/to/MyFile.js' did not match any file(s) known to git.`

Simplemente seleccione la confirmación anterior (agregue un cursor):

> git checkout bd8374c^ -- full/path/to/MyFile.js
Calaf
fuente
3
Esto es mucho más claro que la respuesta aceptada
Pouyan Khodabakhsh
para la consola de Windows (cmd), use find en lugar de grep en el paso 2: git log --diff-filter=D --summary | find "delete" | find "MyFile"y step3, tenga en cuenta las comillas alrededor del hash:git checkout "bd8374c^" -- full/path/to/MyFile.js
user5542121
30

¡@Amber dio la respuesta correcta! Solo una adición más, si no conoce la ruta exacta del archivo, ¡puede usar comodines! Esto funcionó para mí.

git log --all -- **/thefile.*
Petur Subev
fuente
44
@PedroMorteRolo Hmm. No sé cómo me siento al copiar una respuesta existente en la más votada: / Esta respuesta también fue útil por sí sola; un voto a favor podría haber sido suficiente?
Clément
1
Esto no encuentra el archivo si está en la raíz del proyecto (probado en Cygwin).
wortwart
19

A continuación se muestra un comando simple, donde un usuario dev o git puede pasar un nombre de archivo eliminado del directorio raíz del repositorio y obtener el historial:

git log --diff-filter=D --summary | grep filename | awk '{print $4; exit}' | xargs git log --all -- 

Si alguien puede mejorar el comando, por favor hágalo.

Jason
fuente
1
¡Genial gracias! Parece que mi archivo nunca existieron, pero eso es una cuestión separada y mucho más peludo ...
asegúrese de ejecutar esto desde el directorio raíz del repositorio si su archivo parece estar 'perdido'
samaspin
Gracias @samaspin actualizó la respuesta.
Jason
18

Intente usar uno de los visores, de gitkmodo que pueda navegar por el historial para encontrar ese archivo medio recordado. (usar gitk --allsi es necesario para todas las ramas)

Philip Oakley
fuente
44
Esa --allopción es crítica tanto para su respuesta como para la respuesta aceptada.
placas
3
Navegar por la historia tomará una cantidad extraordinaria de tiempo para la mayoría de los proyectos.
mikemaccana
5

Resumen:

  1. Paso 1

Busca la ruta completa de su archivo en el historial de archivos eliminados git log --diff-filter=D --summary | grep filename

  1. Paso 2

Restaura el archivo de confirmación antes de que se elimine

restore () {
  filepath="$@"
  last_commit=$(git log --all --full-history -- $filepath | grep commit | head -1 | awk '{print $2; exit}')
  echo "Restoring file from commit before $last_commit"
  git checkout $last_commit^ -- $filepath
}

restore my/file_path
srghma
fuente
0

Aquí está mi solución:

git log --all --full-history --oneline -- <RELATIVE_FILE_PATH>
git checkout <COMMIT_SHA>^ -- <RELATIVE_FILE_PATH>
Antonio Petricca
fuente