¿Cómo recuperar un solo archivo de una revisión específica en Git?

832

Tengo un repositorio de Git y me gustaría ver cómo se veían algunos archivos hace unos meses. Encontré la revisión en esa fecha; es 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8. Necesito ver cómo se ve un archivo y también guardarlo como un archivo ("nuevo").

Logré ver el archivo usando gitk, pero no tiene una opción para guardarlo. Lo intenté con herramientas de línea de comandos, lo más cerca que estuve fue:

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

Sin embargo, este comando muestra un diff, y no el contenido del archivo. Sé que luego puedo usar algo como PAGER=caty redirigir la salida a un archivo, pero no sé cómo llegar al contenido real del archivo.

Básicamente, estoy buscando algo como svn cat .

Milan Babuškov
fuente
73
La clave aquí: git show(sin ayuda) usa una sintaxis diferente con dos puntos. git show 2c7cf:my_file.txt
Steve Bennett
44
Para aclarar aún más, el comando anterior le está pidiendo a git que muestre dos objetos separados, una revisión y un archivo. La respuesta aceptada a continuación, que utiliza dos puntos entre los dos elementos, es solicitar un archivo específico en una revisión específica.
jhclark
2
En * nix no necesita PAGER, solo redirección de salida de shell con>
Konstantin Pelepelin
posible duplicado de ¿Hay un comando git rápido para ver una versión anterior de un archivo?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Checat tiene un comentario importante, para aquellos que desean exportar el contenido a algún archivo. Necesita algo como esto: git show {sha}: my_file.txt> old_my_file.txt
ormurin

Respuestas:

744

Para completar su propia respuesta, la sintaxis es

git show object
git show $REV:$FILE
git show somebranch:from/the/root/myfile.txt
git show HEAD^^^:test/test.py

El comando toma el estilo habitual de revisión, lo que significa que puede usar cualquiera de los siguientes:

  1. nombre de la sucursal (como se sugirió por la ceniza )
  2. HEAD + x número de ^ caracteres
  3. El hash SHA1 de una revisión dada
  4. Los primeros pocos (quizás 5) caracteres de un hash SHA1 determinado

Consejo Es importante recordar que cuando use " git show", siempre especifique una ruta desde la raíz del repositorio , no su posición actual en el directorio.

(Aunque Mike Morearty menciona que, al menos con git 1.7.5.4, puede especificar una ruta relativa colocando " ./" al comienzo de la ruta, por ejemplo:

git show HEAD^^:./test.py

)


Con Git 2.23+ (agosto de 2019), también puede usar el git restore que reemplaza el git checkoutcomando confuso

git restore -s <SHA1>     -- afile
git restore -s somebranch -- afile

Eso restauraría en el árbol de trabajo solo el archivo como presente en el "origen" ( -s) confirma SHA1 o rama somebranch.
Para restaurar también el índice:

git restore -s <SHA1> -SW -- afile

( -SW: abreviatura de --staged --worktree)


Antes de git1.5.x, eso se hizo con algunas tuberías:

git ls-tree <rev>
muestra una lista de uno o más objetos 'blob' dentro de una confirmación

git cat-file blob <file-SHA1>
cat un archivo como se ha confirmado dentro de una revisión específica (similar a svn cat). use git ls-tree para recuperar el valor de un archivo dado-sha1

git cat-file -p $(git-ls-tree $REV $file | cut -d " " -f 3 | cut -f 1)::

git-ls-tree enumera el ID de objeto para $ file en la revisión $ REV, esto se corta de la salida y se usa como argumento para git-cat-file, que realmente debería llamarse git-cat-object, y simplemente vuelca ese objeto a stdout.


Nota: desde Git 2.11 (Q4 2016), ¡puede aplicar un filtro de contenido a la git cat-filesalida!

Ver commit 3214594 , commit 7bcf341 (09 de septiembre de 2016), commit 7bcf341 (09 de septiembre de 2016) y commit b9e62f6 , commit 16dcc29 (24 de agosto de 2016) por Johannes Schindelin ( dscho) .
(Fusionada por Junio ​​C Hamano - gitster- en commit 7889ed2 , 21 sep 2016)

cat-file: apoyo --textconv / --filtersen modo por lotes

Aunque " git hash-objects", que es una herramienta para tomar un flujo de datos en el sistema de archivos y ponerlo en el almacén de objetos de Git, permitió realizar las conversiones de "fuera del mundo a Git" (por ejemplo, conversiones de fin de línea y aplicación del filtro limpio), y tenía la característica activada por defecto desde los primeros días, su operación inversa " git cat-file", que toma un objeto del almacén de objetos Git y lo externaliza para el consumo del mundo exterior, carecía de un mecanismo equivalente para ejecutar el "Git-to-outside-world"

git config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <"
git cat-file --textconv --batch

Nota: " git cat-file --textconv" comenzó a segfaularse recientemente (2017), que se ha corregido en Git 2.15 (Q4 2017)

Ver commit cc0ea7c (21 de septiembre de 2017) por Jeff King ( peff) .
(Fusionada por Junio ​​C Hamano - gitster- en commit bfbc2fc , 28 sep 2017)


Tenga en cuenta que para anular / reemplazar un archivo con un contenido anterior, ya no debe usar el comando confusogit checkout , pero git restore(Git 2.23+, agosto de 2019)

git restore -s <SHA1> -- afile

Eso restauraría en el árbol de trabajo solo el archivo como presente en el "origen" ( -s) confirma SHA1.
Para restaurar también el índice:

git restore -s <SHA1> -SW -- afile

( -SW: abreviatura de --staged --worktree)

VonC
fuente
66
@Oscar ya que git showesencialmente volca el contenido en la stdout(salida estándar), simplemente puede redirigir esa salida a cualquier archivo que desee ( tldp.org/LDP/abs/html/io-redirection.html ).
VonC
8
git checkout [branch | revision] filepathes el comando correcto
Gaui
12
@Gaui pero git checkoutpodría invalidar su archivo por otra versión, a diferencia de git show, que le permite guardar con un nombre diferente, con el fin de obtener y ver tanto (la versión actual y la versión anterior). No queda claro a partir de la pregunta si el OP quiere reemplazar su versión actual por una antigua.
VonC
99
Me gustaría señalar que ^^^también se puede escribir de manera más general como ~~~o, mejor ~3,. El uso de tildes también tiene la ventaja de no activar la coincidencia de nombre de archivo de algunos shells (zsh, por ejemplo).
Eric O Lebigot
2
No tengo un git suficientemente viejo para verificar: ¿la versión anterior a 1.5.x git rev-parsemaneja la rev:pathsintaxis? (En un git más reciente que pueda git cat-file -p $REV:path. Sin embargo, git showfunciona para rutas de directorio, así, por lo que no es sólo más corto, por lo general más cerca de lo que uno quiere.)
torek
510

Si desea reemplazar / sobrescribir el contenido de un archivo en su rama actual con el contenido del archivo de una confirmación anterior o una rama diferente, puede hacerlo con estos comandos:

git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt

o

git checkout mybranchname path/to/file.txt

Luego tendrá que confirmar esos cambios para que sean efectivos en la rama actual.

California
fuente
44
La solución más simple y para eso está diseñado git-checkout: especificar el nombre de ruta significa que solo se extrae el archivo coincidente. Desde la página de manual de git-checkout: git checkout master ~ 2 Makefile
RichVel
1
Entonces, ¿cómo vuelve al estado anterior antes de ejecutar este comando?
Flint
@Flint si viene del estado HEAD, sería tan simple como git checkout HEAD - [ruta completa].
Tiago Espinha
72
Tenga en cuenta que esto sobrescribe el archivo existente en esa ruta, mientras que la git show SHA1:PATHsolución solo se imprime en stdout.
Flimm
¡Agradable! No habría podido resolver esto mirando git help checkout. Tuve que pagar un subdirectorio a partir de una fecha determinada, y usando este enfoque, pude hacer que esta sintaxis funcionara:git checkout @{YYYY-MM-DD} sub-dir
haridsv
150

Debe proporcionar la ruta completa al archivo:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt
Milan Babuškov
fuente
77
no tiene que ser camino completo. Ruta de acceso de directorio raíz Git (los que llegaron git show --name-onlyes suficiente demasiado
Mohsen
77
Erm, ruta completa desde la raíz del repositorio. Mire mejor el ejemplo que he dado. No hay una barra inclinada antes de "completo".
Milan Babuškov
77
Para su información, si está en un subdirectorio, también puede usar ./filename.ext con éxito.
Viajero
Creo que el punto es que si estás dentro full/repo/path/toe intentas: git show 27cf8e84:my_file.txtserás recompensado con un mensaje como: fatal: la ruta 'full / repo / path / to / my_file.txt' existe, pero no 'my_file.txt' . ¿Quiso decir '27cf8e84: full / repo / path / to / my_file.txt', también conocido como '27cf8e84: ./ my_file.txt'? Es como, Git podría haber ayudado directamente, pero eligió ser pedante aquí.
Ed Randall
101

La forma más fácil es escribir:

git show HASH:file/path/name.ext > some_new_name.ext

dónde:

  • HASH es el número de hash SHA-1 de revisión de Git
  • file / path / name.ext es el nombre del archivo que está buscando
  • some_new_name.ext es la ruta y el nombre donde se debe guardar el archivo antiguo

Ejemplo

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:my_file.txt > my_file.txt.OLD

Esto guardará my_file.txt de la revisión 27cf8e como un nuevo archivo con nombre my_file.txt.OLD

Fue probado con Git 2.4.5.

Si desea recuperar el archivo eliminado , puede usarlo HASH~1(una confirmación antes de HASH especificado).

EJEMPLO:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8~1:deleted_file.txt > deleted_file.txt
jmarceli
fuente
1
Información adicional: Puede obtener el HASH, por ejemplo, con git log
xotix
@xotix Gracias. Tengo toda la historia HASH de un archivo en particular utilizandogit log file/path/name.ext
Sriram Kannan
11

En Windows, con Git Bash:

  • en su espacio de trabajo, cambie el directorio a la carpeta donde vive su archivo
  • git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext
Alessandro Jacopson
fuente
8

Y para volcarlo en un archivo (al menos en Windows) - Git Bash:

$ echo "`git show 60d8bdfc:src/services/LocationMonitor.java`" >> LM_60d8bdfc.java

Las "comillas son necesarias para preservar las nuevas líneas.

Mr_and_Mrs_D
fuente
Buena esa. +1. Buena adición a la git showsintaxis que menciono anteriormente.
VonC 01 de
23
Realmente no entiendo por qué usarías echo, con o sin las comillas. Y no entiendo por qué querrías la forma anexar de redirección de salida. ¿No sería mejor simplemente escribir: git show 60d8bdfc: src / services / LocationMonitor.java> LM_60d8bdfc.java Si por alguna razón realmente quisiera forzar terminaciones de línea de dos estilos, podría canalizarlo a través de unix2dos. Pero nunca me ha resultado útil retener las terminaciones de línea de dos en Windows, ya que cualquier herramienta de texto que no sea el bloc de notas que he usado en Windows maneja líneas de estilo unix muy bien.
hollín
44
git show 60d8bdfc: src / services / LocationMonitor.java >> LM_60d8bdfc.java funcionó para mí.
Mike6679
@ Mike: ¿estás en Windows?
Mr_and_Mrs_D
2
no use comillas dobles porque si los caracteres de su archivo que se parecen a una variable de shell, es decir, $ LANG, serán reemplazados. @ LưuVĩnhPhúc es ahorrador. tampoco use >> Agregará el archivo si existía y podría provocar errores
theguy
3

Esto lo ayudará a obtener todos los archivos eliminados entre confirmaciones sin especificar la ruta, útil si hay muchos archivos eliminados.

git diff --name-only --diff-filter=D $commit~1 $commit | xargs git checkout $commit~1
Adrian Gunawan
fuente
1
git checkout {SHA1} -- filename

Este comando obtiene el archivo copiado de confirmación específica.

jsina
fuente
-2

Obtenga el archivo de una confirmación previa mediante la extracción de la confirmación previa y copiando el archivo.

  • Tenga en cuenta en qué rama se encuentra: git branch
  • Verifique la confirmación anterior que desea: git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • Copie el archivo que desea en una ubicación temporal
  • Verifique la rama desde la que comenzó: git checkout theBranchYouNoted
  • Copie el archivo que colocó en una ubicación temporal
  • Compromete tu cambio a git: git commit -m "added file ?? from previous commit"
rocketInABog
fuente