Trova quando un file è stato eliminato in Git


1035

Ho un repository Git con n commit.

Ho un file di cui ho bisogno, che era nel repository, e che improvvisamente cerco e penso "Oh! Dove sarebbe andato quel file?"

C'è un (serie di) comando (i) Git che mi dirà che "il file really_needed.txt è stato cancellato al commit n-13"?

In altre parole, senza guardare ogni singolo commit e senza sapere che il mio repository Git ha tutte le modifiche di ogni file, posso trovare rapidamente l'ultimo commit che ha quel file, così posso recuperarlo?



2
Il link condiviso da Pedro ha dato la risposta alla mia domanda: come trovare un file cancellato quando non ricordi il percorso.
Gordon Bean,

Risposte:


1127

git log --full-history -- [file path] mostra le modifiche di un file, funziona anche se il file è stato eliminato.

Esempio:

git log --full-history  -- myfile

Se vuoi vedere solo l'ultimo commit, che ha eliminato un file usa -1 in aggiunta, ad es. git log --full-history -1 -- [file path]

Vedi Quale commit ha eliminato un file


16
è possibile cercare modelli? Ho dimenticato il nome completo del file = (forse è possibile ottenere un registro di tutte le eliminazioni?
wutzebaer,


6
Nota: se si utilizza PowerShell, è necessario eseguire l'escape dei trattini: git log '-' [percorso file]. Spero che questo possa uguagliare qualcun altro a digrignare i denti.
A. Wilson,

68
Sono stato in grado di cercare utilizzando git log -- */<<filename>>.<<file extension>>non conoscendo l'intero percorso del file.
Tom Howard,

2
Le parentesi quadre @MERose sono presenti come segnaposto per il percorso del file reale.
Emile Bergeron,

229

Risposta breve:

git log --full-history -- your_file

ti mostrerò tutti i commit nella storia del tuo repository, inclusi i commit di unione, che sono stati toccati your_file. L'ultimo (in alto) è quello che ha eliminato il file.

Qualche spiegazione:

La --full-historybandiera qui è importante. Senza di essa, Git esegue la "semplificazione della cronologia" quando viene richiesta la registrazione di un file. I documenti sono chiari sui dettagli di come funziona esattamente e mi manca la grinta e il coraggio necessari per cercare di capirlo dal codice sorgente, ma i documenti di git-log hanno molto da dire:

Modalità di default

Semplifica la storia alla storia più semplice spiegando lo stato finale dell'albero. Più semplice perché elimina alcuni rami laterali se il risultato finale è lo stesso (cioè unendo i rami con lo stesso contenuto)

Questo ovviamente riguarda quando il file di cui vogliamo la cronologia viene eliminato , poiché la cronologia più semplice che spiega lo stato finale di un file eliminato non è cronologia . Esiste il rischio che git logsenza --full-historyvolontà si possa semplicemente affermare che il file non è mai stato creato? Sfortunatamente sì. Ecco una dimostrazione:

mark@lunchbox:~/example$ git init
Initialised empty Git repository in /home/mark/example/.git/
mark@lunchbox:~/example$ touch foo && git add foo && git commit -m "Added foo"
[master (root-commit) ddff7a7] Added foo
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 foo
mark@lunchbox:~/example$ git checkout -b newbranch
Switched to a new branch 'newbranch'
mark@lunchbox:~/example$ touch bar && git add bar && git commit -m "Added bar"
[newbranch 7f9299a] Added bar
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 bar
mark@lunchbox:~/example$ git checkout master
Switched to branch 'master'
mark@lunchbox:~/example$ git rm foo && git commit -m "Deleted foo"
rm 'foo'
[master 7740344] Deleted foo
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 foo
mark@lunchbox:~/example$ git checkout newbranch
Switched to branch 'newbranch'
mark@lunchbox:~/example$ git rm bar && git commit -m "Deleted bar"
rm 'bar'
[newbranch 873ed35] Deleted bar
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 bar
mark@lunchbox:~/example$ git checkout master
Switched to branch 'master'
mark@lunchbox:~/example$ git merge newbranch
Already up-to-date!
Merge made by the 'recursive' strategy.
mark@lunchbox:~/example$ git log -- foo
commit 77403443a13a93073289f95a782307b1ebc21162
Author: Mark Amery 
Date:   Tue Jan 12 22:50:50 2016 +0000

    Deleted foo

commit ddff7a78068aefb7a4d19c82e718099cf57be694
Author: Mark Amery 
Date:   Tue Jan 12 22:50:19 2016 +0000

    Added foo
mark@lunchbox:~/example$ git log -- bar
mark@lunchbox:~/example$ git log --full-history -- foo
commit 2463e56a21e8ee529a59b63f2c6fcc9914a2b37c
Merge: 7740344 873ed35
Author: Mark Amery 
Date:   Tue Jan 12 22:51:36 2016 +0000

    Merge branch 'newbranch'

commit 77403443a13a93073289f95a782307b1ebc21162
Author: Mark Amery 
Date:   Tue Jan 12 22:50:50 2016 +0000

    Deleted foo

commit ddff7a78068aefb7a4d19c82e718099cf57be694
Author: Mark Amery 
Date:   Tue Jan 12 22:50:19 2016 +0000

    Added foo
mark@lunchbox:~/example$ git log --full-history -- bar
commit 873ed352c5e0f296b26d1582b3b0b2d99e40d37c
Author: Mark Amery 
Date:   Tue Jan 12 22:51:29 2016 +0000

    Deleted bar

commit 7f9299a80cc9114bf9f415e1e9a849f5d02f94ec
Author: Mark Amery 
Date:   Tue Jan 12 22:50:38 2016 +0000

    Added bar

Si noti come git log -- barnel dump del terminale sopra riportato non abbia prodotto letteralmente output; Git sta "semplificando" la storia in una finzione dove barnon è mai esistita. git log --full-history -- bard'altra parte, ci dà il commit che ha creato bare il commit che lo ha eliminato.

Per essere chiari: questo problema non è solo teorico. Ho solo esaminato i documenti e scoperto il--full-history bandiera perché git log -- some_filenon riuscivo per me in un vero repository in cui stavo cercando di rintracciare un file eliminato. La semplificazione della cronologia a volte può essere utile quando stai cercando di capire come un file attualmente esistente è arrivato al suo stato attuale, ma quando cerchi di rintracciare una cancellazione di file è più probabile che ti rovini nascondendo il commit che ti interessa . Usa sempre la --full-historybandiera per questo caso d'uso.


4
Si noti che questo cerca solo la cronologia rilevante per il ramo corrente (non "tutta la cronologia repository") ... vale a dire se il file non è ancora stato cancellato nel ramo corrente ma è stato in un altro ramo, non verrà trovato il commit di eliminazione. Devi essere su qualsiasi ramo in cui il file è già stato eliminato . Forse è ovvio quando ci penso, ma all'inizio mi ha sorpreso.
Anentropico

1
Questa risposta funziona. Ma git logdall'output stesso, non è affatto ovvio che l'ultimo commit abbia eliminato il file. Ho anche provato git log --name-status --full-history -- file_namee git log -p --stat --full-history -- file_name, ma nessuno dei due indica esplicitamente che il file è stato rimosso nell'ultimo commit. Sembra un bug.
Martin_W,

@Martin_ATS mkdir somedir && cd somedir && git init && touch foo && git add foo && git commit -m "Added foo" && git checkout -b newbranch && touch bar && git add bar && git commit -m "Added bar" && git checkout master && git rm foo && git commit -m "Deleted foo" && git checkout newbranch && git rm bar && git commit -m "Deleted bar" && git checkout master && git merge newbranch && git log --name-status --full-history -- barinclude D bare A barper me nell'output del registro con Git 2.12.2. Non vedi quelle righe nell'output? Quale versione hai?
Mark Amery,

git version 2.15.1Sì, la sequenza di comandi riporta D bare A bar. Forse il mio problema è particolare della storia del mio file. Stavo tracciando la storia di un .htaccessfile che è stato rimosso e rimosso da Gitignore. Alla fine l'ho capito e ho aggiunto il file. Quando includo --name-statusil git logcomando, vedo due A .htaccessvoci (da quando l'ho aggiunto nell'ultimo commit) ma no D .htaccess. Così sembra che in alcuni casi, anche se un file è stato rimosso dal repository, git lognon mostrerà una D file_namevoce esplicita .
Martin_W,

@Martin_ATS Curioso. Mi chiedo se forse sono .htaccessstati aggiunti in un commit X ma non inclusi nel commit di merge che ha portato X sul master? Questa è l'unica cosa a cui riesco a pensare che potrei sostenere che dovrebbe apparire come un file che è stato aggiunto e mai cancellato e che tuttavia non è ancora presente. Sarebbe interessante provare a capire un MCVE, quindi capire se si tratta di un bug Git e, in caso contrario, se è possibile modificare la mia risposta per gestire il tuo caso.
Mark Amery,

84

Accedi a Git ma devi aggiungere il prefisso al percorso --

Per esempio:

dan-mac:test dani$ git log file1.txt
fatal: ambiguous argument 'file1.txt': unknown revision or path not in the working tree.

dan-mac:test dani$ git log -- file1.txt
 commit 0f7c4e1c36e0b39225d10b26f3dea40ad128b976
 Author: Daniel Palacio <danpal@gmail.com>
 Date:   Tue Jul 26 23:32:20 2011 -0500

 foo

31

Ho appena aggiunto una soluzione qui (c'è un modo in git per elencare tutti i file eliminati nel repository?) Per trovare i commit dei file eliminati usando un regexp:

git log --diff-filter=D --summary | sed -n '/^commit/h;/\/some_dir\//{G;s/\ncommit \(.*\)/ \1/gp}'

Ciò restituisce tutto ciò che è stato cancellato all'interno di una directory denominata some_dir(a cascata). Qualsiasi sed regexp là dove \/some_dir\/è farà.

OSX (grazie a @triplee e @keif)

git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }

1
Bello. Qualche discrepanza sotto bash in OS X:sed: 1: "/^commit/h;/\/some_dir\ ...": bad flag in substitute command: '}'
Brent Faust

@BrentFoust È un peccato che non riesco a testarlo ... prova ad aggiungere uno spazio alla fine (dopo le parentesi graffe ma prima della singola citazione), la pagina man online non è chiara al riguardo ...
estani

Bel suggerimento. Ma l'aggiunta di uno spazio prima della singola citazione non ha aiutato. Né ha fatto uno spazio prima della parentesi graffa di chiusura.
Brent Faust,

1
sedApparentemente BSD / OSX non è sempre buono con i punti e virgola come separatori di comandi. Prova a cambiarli in newline o passa ased -n -e '/^commit/h' -e '\:/some_dir/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }
tripleee

1
L'ho provato e ha git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }lavorato per me su OSX.
keif

21

È possibile trovare l'ultimo commit che ha eliminato il file come segue:

git rev-list -n 1 HEAD -- [file_path]

Ulteriori informazioni sono disponibili qui


11
La soluzione primaria votata non ha funzionato per me, ma questa ha funzionato.
Nick Heiner,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.