Comment récupérer un seul fichier d'une révision spécifique dans Git?

833

J'ai un référentiel Git et j'aimerais voir à quoi ressemblaient certains fichiers il y a quelques mois. J'ai trouvé la révision à cette date; c'est 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8. J'ai besoin de voir à quoi ressemble un fichier et de l'enregistrer en tant que ("nouveau") fichier.

J'ai réussi à voir le fichier à l'aide gitk, mais il n'a pas d'option pour l'enregistrer. J'ai essayé avec des outils en ligne de commande, le plus proche que j'ai obtenu était:

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

Cependant, cette commande affiche un diff et non le contenu du fichier. Je sais que je peux plus tard utiliser quelque chose comme PAGER=catet rediriger la sortie vers un fichier, mais je ne sais pas comment accéder au contenu du fichier réel.

Fondamentalement, je recherche quelque chose comme svn cat .

Milan Babuškov
la source
73
La clé ici: git show(sans aide) utilise une syntaxe différente avec deux points. git show 2c7cf:my_file.txt
Steve Bennett
4
Pour clarifier davantage, la commande ci-dessus demande à git d'afficher deux objets distincts, une révision et un fichier. La réponse acceptée ci-dessous, qui utilise deux points entre les deux éléments, demande un fichier spécifique à une révision spécifique.
jhclark
2
Sur * nix, vous n'avez pas besoin de PAGER, juste la redirection de sortie du shell avec>
Konstantin Pelepelin
doublon possible de Y a
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Checat a un commentaire important, pour ceux qui veulent que le contenu soit exporté dans un fichier. Vous avez besoin de quelque chose comme ceci: git show {sha}: my_file.txt> old_my_file.txt
ormurin

Réponses:

744

Pour compléter votre propre réponse, la syntaxe est en effet

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

La commande prend le style de révision habituel, ce qui signifie que vous pouvez utiliser l'une des méthodes suivantes:

  1. nom de la branche (comme suggéré par ash )
  2. HEAD+ x nombre de ^caractères
  3. Le hachage SHA1 d'une révision donnée
  4. Les premiers (peut-être 5) caractères d'un hachage SHA1 donné

Astuce Il est important de se rappeler que lorsque vous utilisez " git show", spécifiez toujours un chemin à partir de la racine du référentiel , pas votre position actuelle dans le répertoire.

(Bien que Mike Morearty mentionne que, au moins avec git 1.7.5.4, vous pouvez spécifier un chemin relatif en mettant " ./" au début du chemin - par exemple:

git show HEAD^^:./test.py

)


Avec Git 2.23+ (août 2019), vous pouvez également utiliser git restore ce qui remplace la git checkoutcommande confuse

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

Cela ne restaurerait dans l'arborescence de travail que le fichier tel qu'il est présent dans la branche "source" ( -s) de validation SHA1 somebranch.
Pour restaurer également l'index:

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

( -SW: abréviation de --staged --worktree)


Avant git1.5.x, cela se faisait avec de la plomberie:

git ls-tree <rev>
afficher une liste d'un ou plusieurs objets "blob" dans une validation

git cat-file blob <file-SHA1>
cat un fichier car il a été validé dans une révision spécifique (similaire à svn cat). utilisez git ls-tree pour récupérer la valeur d'un fichier-sha1 donné

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

git-ls-tree répertorie l'ID d'objet pour $ file dans la révision $ REV, il est coupé de la sortie et utilisé comme argument pour git-cat-file, qui devrait vraiment être appelé git-cat-object, et simplement les dumps cet objet à stdout.


Remarque: depuis Git 2.11 (Q4 2016), vous pouvez appliquer un filtre de contenu à la git cat-filesortie!

Voir commit 3214594 , commit 7bcf341 (09 sept. 2016), commit 7bcf341 (09 sept. 2016) et commit b9e62f6 , commit 16dcc29 (24 août 2016) par Johannes Schindelin ( dscho) .
(Fusionné par Junio ​​C Hamano - gitster- en commit 7889ed2 , 21 sept. 2016)

cat-file: support --textconv/ --filtersen mode batch

Même si " git hash-objects", qui est un outil pour prendre un flux de données sur un système de fichiers et le placer dans le magasin d'objets Git, a permis d'effectuer les conversions "du monde extérieur vers Git" (par exemple, les conversions de fin de ligne et l'application du filtre propre), et il avait la fonction activée par défaut dès les premiers jours, son fonctionnement inverse " git cat-file", qui prend un objet de la boutique d'objets Git et l'extériorise pour la consommation par le monde extérieur, manquait d'un mécanisme équivalent pour exécuter le "Git-to-outside-world"

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

Remarque: " git cat-file --textconv" a commencé à segfaulting récemment (2017), qui a été corrigé dans Git 2.15 (Q4 2017)

Voir commit cc0ea7c (21 sept. 2017) de Jeff King ( peff) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit bfbc2fc , 28 sept. 2017)


Notez que pour remplacer / remplacer un fichier par un contenu passé, vous ne devez plus utiliser la commande confusegit checkout , mais git restore(Git 2.23+, août 2019)

git restore -s <SHA1> -- afile

Cela ne restaurerait sur l'arborescence de travail que le fichier présent dans le -scommit "source" ( ) SHA1.
Pour restaurer également l'index:

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

( -SW: abréviation de --staged --worktree)

VonC
la source
6
@Oscar étant donné que git showle contenu est essentiellement vidé sur la stdout(sortie standard), vous pouvez simplement rediriger cette sortie vers le fichier de votre choix ( tldp.org/LDP/abs/html/io-redirection.html ).
VonC
8
git checkout [branch | revision] filepathest la bonne commande
Gaui
12
@Gaui mais git checkoutserait remplacer votre fichier par une autre version, par opposition à git show, qui vous permet de l'enregistrer sous un autre nom, pour vous d'obtenir et de voir à la fois (la version actuelle et l'ancienne version). La question ne permet pas de savoir si le PO souhaite remplacer sa version actuelle par une ancienne.
VonC
9
Je voudrais noter que ^^^peut également être écrit plus généralement ~~~ou, mieux, ~3. L'utilisation de tildes a également l'avantage de ne pas déclencher la correspondance de nom de fichier de certains shells (zsh, par exemple).
Eric O Lebigot
2
Je n'ai pas de git suffisamment ancien pour vérifier: la pré-1.5.x git rev-parsegère- rev:patht-elle la syntaxe? (Dans un git plus récent, vous pouvez git cat-file -p $REV:path. Cependant, cela git showfonctionne aussi pour les chemins de répertoire, donc ce n'est pas seulement plus court, il est généralement plus proche de ce que l'on veut.)
torek
510

Si vous souhaitez remplacer / écraser le contenu d'un fichier dans votre branche actuelle par le contenu du fichier d'une validation précédente ou d'une branche différente, vous pouvez le faire avec ces commandes:

git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt

ou

git checkout mybranchname path/to/file.txt

Vous devrez ensuite valider ces modifications pour qu'elles soient effectives dans la branche actuelle.

Californie
la source
4
C'est la solution la plus simple et c'est pour cela que git-checkout est conçu - spécifier le chemin signifie que seul le fichier correspondant est extrait. Depuis la page de manuel de git-checkout: git checkout master ~ 2 Makefile
RichVel
1
Ensuite, comment revenir à l'état précédent avant d'exécuter cette commande?
Flint
@Flint si vous venez de l'état HEAD, ce serait aussi simple que git checkout HEAD - [chemin complet].
Tiago Espinha
72
Notez que cela écrase le fichier existant dans ce chemin, tandis que la git show SHA1:PATHsolution imprime uniquement sur stdout.
Flimm
Agréable! Je n'aurais pas pu comprendre cela en regardant git help checkout. J'ai dû extraire un sous-répertoire à partir d'une certaine date, et en utilisant cette approche, j'ai pu faire fonctionner cette syntaxe:git checkout @{YYYY-MM-DD} sub-dir
haridsv
150

Vous devez fournir le chemin d'accès complet au fichier:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt
Milan Babuškov
la source
7
n'a pas besoin d'être complet. Chemin depuis le répertoire racine de git (ceux qui sont entrés git show --name-onlysuffisent aussi
Mohsen
7
Erm, chemin complet depuis la racine du référentiel. Jetez un coup d'œil à l'exemple que j'ai donné. Il n'y a pas de barre oblique avant "plein".
Milan Babuškov
7
Pour info, si vous êtes dans un sous-répertoire, vous pouvez également utiliser ./filename.ext avec succès.
Voyageur
Je pense que le fait est que si vous êtes dedansfull/repo/path/to et que vous essayez :,git show 27cf8e84:my_file.txt vous serez récompensé par un message comme: fatal: le chemin d'accès 'full / repo / path / to / my_file.txt' existe, mais pas 'my_file.txt' . Voulez-vous dire '27cf8e84: full / repo / path / to / my_file.txt' aka '27cf8e84: ./ my_file.txt'? C'est comme si Git aurait pu aider directement, mais a choisi d'être pédant ici.
Ed Randall
101

Le plus simple est d'écrire:

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

où:

  • HASH est le numéro de hachage SHA-1 de la révision Git
  • fichier / chemin / nom.ext est le nom du fichier que vous recherchez
  • some_new_name.ext est le chemin et le nom où l'ancien fichier doit être enregistré

Exemple

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

Cela sauvera mon_fichier.txt de la révision 27cf8e en tant que nouveau fichier avec le nom mon_fichier.txt.OLD

Il a été testé avec Git 2.4.5.

Si vous souhaitez récupérer le fichier supprimé , vous pouvez utiliserHASH~1 (un commit avant le HASH spécifié).

EXEMPLE:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8~1:deleted_file.txt > deleted_file.txt
jmarceli
la source
1
Informations supplémentaires: Vous pouvez obtenir le HASH par exemple avec git log
xotix
@xotix Merci. J'ai eu tout l'historique HASH pour un fichier particulier en utilisantgit log file/path/name.ext
Sriram Kannan
11

Sous Windows, avec Git Bash:

  • dans votre espace de travail, changez dir dans le dossier où se trouve votre fichier
  • git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext
Alessandro Jacopson
la source
8

Et pour bien le vider dans un fichier (sur Windows au moins) - Git Bash:

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

Les "guillemets sont nécessaires pour préserver les nouvelles lignes.

Mr_and_Mrs_D
la source
Joli. +1. Bon ajout sur la git showsyntaxe que je mentionne ci-dessus.
VonC
23
Je ne comprends vraiment pas pourquoi vous utiliseriez l'écho, avec ou sans les guillemets. Et je ne comprends pas pourquoi vous voudriez la forme d'ajout de redirection de sortie. Ne serait-il pas préférable d'écrire simplement: git show 60d8bdfc: src / services / LocationMonitor.java> LM_60d8bdfc.java Si, pour une raison quelconque, vous vouliez réellement forcer les fins de ligne de style dos, vous pourriez le diriger via unix2dos. Mais je n'ai jamais trouvé le moins du monde utile de conserver les fins de ligne DOS sous Windows, car tout outil de texte autre que le bloc-notes que j'ai utilisé sous Windows gère très bien les lignes de style Unix.
sootsnoot
4
git show 60d8bdfc: src / services / LocationMonitor.java >> LM_60d8bdfc.java a fonctionné pour moi.
Mike6679
@Mike: êtes-vous sur Windows?
Mr_and_Mrs_D
2
n'utilisez pas de guillemets doubles car si vos caractères de fichier qui ressemblent à une variable shell, c'est-à-dire $ LANG, ils seront remplacés. @ LưuVĩnhPhúc est économiseur. également ne pas utiliser >> Il ajoutera le fichier s'il existait et pourrait conduire à des erreurs
theguy
3

Cela vous aidera à obtenir tous les fichiers supprimés entre les validations sans spécifier le chemin, utile s'il y a beaucoup de fichiers supprimés.

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

cette commande récupère le fichier copié à partir d'un commit spécifique.

jsina
la source
-2

Obtenez le fichier d'une validation précédente en extrayant le fichier de validation et de copie précédent.

  • Notez la branche sur laquelle vous vous trouvez: git branch
  • Découvrez le précédent commit que vous souhaitez: git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • Copiez le fichier que vous souhaitez vers un emplacement temporaire
  • Découvrez la succursale à partir de laquelle vous êtes parti: git checkout theBranchYouNoted
  • Copiez le fichier que vous avez placé dans un emplacement temporaire
  • Validez votre modification sur git: git commit -m "added file ?? from previous commit"
rocketInABog
la source