Comment trouver un fichier supprimé dans l'historique de validation du projet?

1275

Il était une fois un dossier dans mon projet que j'aimerais maintenant pouvoir récupérer.

Le problème est: je n'ai aucune idée de quand l'ai-je supprimé et de quel chemin il s'agissait.

Comment localiser les validations de ce fichier lorsqu'il existait?

Pedro Rolo
la source
Question similaire ici: stackoverflow.com/questions/7093602/…
eckes
3
Copie
13
Les réponses ici me sont plus utiles que les réponses dans les doublons .
Felipe Alvarez
5
d'accord ... indépendamment des doublons ... ils ne sont pas apparus dans la recherche Google .... celui-ci l'a fait ... j'espère que nous allons arrêter de perdre du temps à courir après les doublons ... seul le temps et l'algorithme de google le feront dites quelle question est la meilleure.
Tim Boland du

Réponses:

1601

Si vous ne connaissez pas le chemin exact que vous pouvez utiliser

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

Si vous connaissez le chemin d'accès du fichier, vous pouvez le faire:

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

Cela devrait afficher une liste des validations dans toutes les branches qui ont touché ce fichier. Ensuite, vous pouvez trouver la version du fichier que vous souhaitez, et l'afficher avec ...

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

Ou restaurez-le dans votre copie de travail avec:

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

Notez le symbole caret ( ^), qui obtient le retrait avant celui identifié, car au moment de la <SHA>validation, le fichier est supprimé, nous devons regarder la validation précédente pour obtenir le contenu du fichier supprimé

ambre
la source
2
Essayez d'utiliser un chemin relatif au lieu d'un chemin absolu (si ce n'est déjà fait).
Ambre
63
Et si vous ne connaissez pas le chemin exact? Tout ce que vous savez, c'est le nom du fichier?
Priestc
17
@PedroMorteRolo git log -- <path>n'aura aucune sortie lorsque vous êtes sur une branche dans laquelle le fichier n'a jamais existé. Vous devez toujours utiliser git log --all -- <path>, pour vous assurer de ne pas manquer les modifications qui se sont produites sur d'autres branches. La commande git log -- <path>peut être très dangereuse si vous avez plusieurs branches et avez tendance à oublier les chemins et les branches (comme moi) et elle est également dangereuse si vous travaillez avec d'autres développeurs.
plaques de cuisson
4
@Amber, pensez à ajouter --all(merci Philip ) à votre git logréponse, afin que les gens ne manquent pas les modifications et les fichiers sur d'autres branches. Cela éviterait aux gens oublieux comme moi beaucoup de chagrin.
plaques de cuisson
3
Comme indiqué dans la réponse ci-dessous, la restauration du fichier devrait être git checkout <SHA>^ -- <path-to-file>(notez le symbole ^), car au moment de la validation de <SHA>, le fichier est supprimé, nous devons regarder la validation précédente pour obtenir le contenu du fichier supprimé
kipelovets
393

Obtenez une liste des fichiers supprimés et copiez le chemin complet du fichier supprimé

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

Exécutez la commande suivante pour trouver l'ID de validation de cette validation et copiez l'ID de validation

git log --all -- FILEPATH

Afficher la différence du fichier supprimé

git show COMMIT_ID -- FILE_PATH

N'oubliez pas que vous pouvez écrire la sortie dans un fichier en utilisant >comme

git show COMMIT_ID -- FILE_PATH > deleted.diff
Fatih Acet
la source
1
Bien que je trouve le chemin avec l' aide de la première étape, la deuxième étape jette cette erreur: unknown revision or path not in the working tree.
jvannistelrooy
6
Pour voir les hachages de validation et les suppressions, vous pouvez le fairegit log --diff-filter=D --summary | grep -E 'delete|^commit\s+\S+'
Chris Middleton
1
L'étape 2 ne renvoie rien. Une idée de pourquoi cela peut arriver? Mon nom de fichier est correct.
Denis Kniazhev
2
Pour trouver combiner les trois en une seule fonction, ajoutez ceci dans votre .bashrc ou .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; }et maintenant vous pouvez simplement faire:git-grep-latest some_text
randomor
1
@TylerJones vous pouvez tout alimenter avec Linux avec des tuyaux - google linux pipes.. vous aimerez ça.
John Hunt
37

Impossible de modifier la réponse acceptée. Ajoutez-la ici comme réponse,

pour restaurer le fichier dans git, utilisez ce qui suit (notez le signe '^' juste après le SHA)

git checkout <SHA>^ -- /path/to/file
Akshay Agarwal
la source
Je ne comprends pas pourquoi vous voudriez le ^. Le fichier est dans le commit avec ce SHA ... pourquoi voudriez-vous revenir en arrière à partir d'un autre commit?
Tony K.
19
Il est dans le commit avec ce sha comme "supprimé" ce qui signifie qu'il n'existera toujours pas. Vous devez aller au commit avant cela pour le récupérer.
tandrewnichols
6
@tandrewnichols, ce qui signifie simplement que vous utilisez le mauvais SHA de commit - vous voulez le commit pour la version du fichier que vous voulez ... qui n'est probablement pas la version où le fichier est supprimé.
Amber
6
@Amber et la validation que vous souhaitez est probablement la plus récente avant sa suppression, d'où cette réponse.
Sam Holder
1
@AlexR: <SHA>~1devrait fonctionner de la même manière sans qu'il soit nécessaire de l'envelopper avec des guillemets.
CodeManX
37

Supposons que vous souhaitiez récupérer un fichier appelé MyFile, mais n'êtes pas sûr de son chemin (ou de son extension, d'ailleurs):

Prelim.: Évitez la confusion en marchant à la racine git

Un projet non trivial peut avoir plusieurs répertoires avec des noms similaires ou identiques.

> cd <project-root>
  1. Trouvez le chemin complet

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

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

full/path/to/MyFile.js est le chemin d'accès et le fichier que vous recherchez.

  1. Déterminez tous les commits qui ont affecté ce fichier

    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. Extraire le fichier

Si vous choisissez le premier commit répertorié (le dernier chronologiquement, ici bd8374c), le fichier ne sera pas trouvé, car il a été supprimé dans ce 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.`

Sélectionnez simplement le précédent (ajouter un signe d'insertion):

> git checkout bd8374c^ -- full/path/to/MyFile.js
Calaf
la source
3
C'est beaucoup plus clair que la réponse acceptée
Pouyan Khodabakhsh
pour la console Windows (cmd), utilisez find au lieu de grep à l'étape 2: git log --diff-filter=D --summary | find "delete" | find "MyFile"Et step3, notez les guillemets autour du hachage:git checkout "bd8374c^" -- full/path/to/MyFile.js
user5542121
30

@Amber a donné la bonne réponse! Encore un ajout, si vous ne connaissez pas le chemin exact du fichier, vous pouvez utiliser des caractères génériques! Cela a fonctionné pour moi.

git log --all -- **/thefile.*
Petur Subev
la source
4
@PedroMorteRolo Hmm. Je ne sais pas ce que je ressens à l'idée de copier une réponse existante dans la réponse la plus votée: / Cette réponse était également utile en elle-même; un vote positif aurait pu suffire?
Clément
1
Il ne trouve pas le fichier s'il se trouve à la racine du projet (testé dans Cygwin).
wortwart
19

Vous trouverez ci-dessous une commande simple, où un utilisateur dev ou git peut passer un nom de fichier supprimé du répertoire racine du référentiel et obtenir l'historique:

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

Si quelqu'un peut améliorer la commande, veuillez le faire.

Jason
la source
1
Super merci! On dirait que mon fichier n'a jamais existé du tout, mais c'est un problème distinct et beaucoup plus épineux ...
assurez-vous de l'exécuter à partir du répertoire racine du référentiel si votre fichier semble être «manquant»
samaspin
Merci @samaspin a mis à jour la réponse.
Jason
18

Essayez d'utiliser l'un des visualiseurs, par exemple gitkpour parcourir l'historique pour trouver ce fichier à moitié mémorisé. (utiliser gitk --allsi nécessaire pour toutes les branches)

Philip Oakley
la source
4
Cette --alloption est essentielle à la fois pour votre réponse et pour la réponse acceptée.
plaques de cuisson
3
La navigation dans l'histoire prendra un temps extraordinaire pour la plupart des projets.
mikemaccana
5

Sommaire:

  1. Étape 1

Vous recherchez le chemin complet de votre fichier dans l'historique des fichiers supprimés git log --diff-filter=D --summary | grep filename

  1. Étape 2

Vous restaurez votre fichier à partir de la validation avant sa suppression

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
la source
0

Voici ma solution:

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