Trova e ripristina un file eliminato in un repository Git


2802

Di 'che sono in un repository Git. Elimina un file e applico tale modifica. Continuo a lavorare e mi impegno ancora. Quindi, trovo che ho bisogno di ripristinare quel file.

So di poter effettuare il checkout di un file utilizzando git checkout HEAD^ foo.bar, ma non so davvero quando è stato eliminato quel file.

  1. Quale sarebbe il modo più rapido per trovare il commit che ha eliminato un determinato nome file?
  2. Quale sarebbe il modo più semplice per ripristinare quel file nella mia copia di lavoro?

Spero di non dover sfogliare manualmente i miei registri, verificare l'intero progetto per un determinato SHA e quindi copiare manualmente quel file nella verifica del mio progetto originale.


39
si noti che il commento precedente risponde alla domanda nel titolo, non nel corpo - che include scoprire quando il file è stato eliminato.
avdgaag,

8
Per trovare il commit è stato eliminato un file in:git log --diff-filter=D -- path/to/file
titaniumdecoy



54
@hhh git checkout deletedFileverrà annullato deletedFilese è stato eliminato ma la cancellazione non è stata ancora messa in scena o impegnata . Non è quello che la domanda qui sta ponendo; questa domanda riguarda come ripristinare un file la cui cancellazione è stata commessa molti commit fa.
Mark Amery,

Risposte:


3150

Trova l'ultimo commit che ha interessato il percorso indicato. Poiché il file non è presente nel commit HEAD, questo commit deve averlo eliminato.

git rev-list -n 1 HEAD -- <file_path>

Quindi controlla la versione al commit prima, usando il ^simbolo caret ( ):

git checkout <deleting_commit>^ -- <file_path>

O in un comando, se $fileè il file in questione.

git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

Se stai usando zsh e l'opzione EXTENDED_GLOB è abilitata, il simbolo del cursore non funzionerà. Puoi usare ~1invece.

git checkout $(git rev-list -n 1 HEAD -- "$file")~1 -- "$file"

94
Il punto difficile è verificare il commit PRIMA, usando il suffisso ^. Grazie.
Christian Oudard,

4
Per qualche motivo, questo non funzionerà in zsh. ± git checkout $(git rev-list -n 1 HEAD "spec/Sporkfile_example.rb")^ -- "spec/Sporkfile_example.rb" zsh: no matches found: b71c152d8f38dcd23ad7600a93f261a7252c59e9^ Sono passato a bash e ha funzionato bene però.
zoras,

20
Dalla riga di comando di Windows ho ricevuto un errore. error: pathspec <filename> did not match any file(s) known to git.. La soluzione era usare git bash.
Donturner,

56
@zoras zsh ha una propria espansione su '^' Credo, ma puoi usare la sintassi alternativa di '~ 1': git checkout <deleting-commit>~1 -- <file-path> ~ X ti consente di specificare X commit prima del commit specificato, quindi ~ 1 è il commit prima, ~ 2 è già stato commesso due volte, ecc.
Nils Luxton,

22
Al prompt di cmd di Windows, il ^personaggio è il carattere di escape! Pertanto, su cmd, devi digitare ^^per dire a cmd che vuoi un singolo letterale ^ e che non stai sfuggendo a qualcos'altro dopo di esso. Ciò che sta accadendo a molte persone è che ^è seguito da uno spazio. Quindi cmd pensa che stai sfuggendo allo spazio, il che produce semplicemente un personaggio spaziale. Quindi, quando git ottiene gli argomenti cli, vede SHA1e non SHA1^ . È veramente noioso. ~non è un personaggio di fuga, quindi è per questo che funziona ancora. (PS. Se pensi che i googler vorranno queste informazioni, per favore vota questo commento)
Alexander Bird

875
  1. Utilizzare git log --diff-filter=D --summaryper ottenere tutti i commit che hanno cancellato i file e i file cancellati;
  2. Utilizzare git checkout $commit~1 path/to/file.extper ripristinare il file eliminato.

Dov'è $commitil valore del commit che hai trovato al passaggio 1, ad ese4cf499627


10
curioso, a cosa si riferisce ~ 1?
Tommy Chheng,

7
@tommy - la specifica tilde ti darà l'ennesimo nipote del commit nominato. Vedi book.git-scm.com/4_git_treeishes.html per maggiori dettagli.
Robert Munteanu,

5
questo è di gran lunga l'approccio più semplice ed intuitivo. git log -- *PartOfMyFileName*. Grazie per il$commit~1
bgs

3
la git checkout $commit~1 filenamesintassi funziona perfettamente per i singoli file e funziona anche per intere directory. vale a dire: per ripristinare tutte le immagini eliminate in ./images da sha 12345: git checkout 12345~1 images. grazie per questa risposta!
noinput

34
@Alexar $commit~1significa che è necessario aggiungere il nome del commit. Qualcosa di simile a 1d0c9ef6eb4e39488490543570c31c2ff594426cdove si $committrova.
Eugene,

319

Per ripristinare tutti quei file eliminati in una cartella, immettere il seguente comando.

git ls-files -d | xargs git checkout --

1
Dove vengono convogliati i file? Non vedo alcun cambiamento.
William Grand,

21
Questo è probabilmente il metodo più semplice. gitHa pervertito la difficoltà di rendere persino il compito più semplice.
1313

git checkout - [file] ripristinerà le modifiche nel [file]. La pipe sostituirà [file] con il nome dei file eliminati.
Manu,

6
Il ls-filescomando secondario è utile, ma non sembra funzionare per i file che sono stati rimossi con, ad git rmesempio, in scena, per non parlare del commit, che è ciò che l'OP ha chiesto.
MarkHu,

Questo ha funzionato per il ripristino dei file eliminati, ma come posso aggiornare i file che sono stati modificati e visualizzati come M myChangedFiledopo git checkout?
libby,

124

Sono arrivato a questa domanda cercando di ripristinare un file che ho appena eliminato ma non avevo ancora eseguito il commit della modifica. Nel caso in cui ti trovi in ​​questa situazione, tutto ciò che devi fare è il seguente:

git checkout HEAD -- path/to/file.ext


93

Se sei pazzo, usa git-bisect. Ecco cosa fare:

git bisect start
git bisect bad
git bisect good <some commit where you know the file existed>

Ora è il momento di eseguire il test automatizzato. Il comando shell '[ -e foo.bar ]'restituirà 0 se foo.baresiste e 1 altrimenti. Il comando "esegui" git-bisectutilizzerà la ricerca binaria per trovare automaticamente il primo commit in cui il test ha esito negativo. Inizia a metà dell'intervallo indicato (da buono a cattivo) e lo taglia a metà in base al risultato del test specificato.

git bisect run '[ -e foo.bar ]'

Ora sei al commit che lo ha eliminato. Da qui, puoi tornare al futuro e utilizzare git-revertper annullare la modifica,

git bisect reset
git revert <the offending commit>

oppure potresti tornare indietro di un commit e ispezionare manualmente il danno:

git checkout HEAD^
cp foo.bar /tmp
git bisect reset
cp /tmp/foo.bar .

2
Potresti approfondire git bisect run '[ -e foo.bar ]'?
avdgaag,

Puoi anche usare il bene e il male manualmente, se è qualcosa che non può essere verificato automaticamente. Vedi la pagina man bisect.
Josh Lee,

1
@avdgaag the git bisect rundice a Git di automatizzare la bisection eseguendo il comando seguendo la parola 'run' dove il comando deve tornare 0per una goodversione (vedere git help bisectper i dettagli). È '[ -e foo.bar ]'un'espressione standard per verificare se il file foo.baresiste (l'implementazione è di solito in un file a /usr/bin/[cui è di solito /usr/bin/testun collegamento fisico) e i singoli segni di citazione sono usati per mettere tutto come un singolo argomento della riga di comando.
Mikko Rantalainen il

Grande idea. Ho provato questo approccio e ha identificato un commit prima dell'eliminazione, ma non il commit che ha effettivamente eliminato il file. E in un altro test ha identificato 2 commit prima della cancellazione.
Michael Osofsky,

Insane? Può essere. Ma bisect è un ottimo modo per aiutare a trovare dove è stato introdotto un bug ed è quindi un'abilità preziosa da imparare comunque. Quindi, anche se forse non è il modo 'corretto' o più 'corretto' qui è comunque una buona idea e vale sicuramente un +1!
Pryftan,

77

Il mio nuovo alias preferito, sulla base di bonyiii 's risposta (upvoted), e la mia risposta su ' passare un argomento a un comando alias Git ':

git config alias.restore '!f() { git checkout $(git rev-list -n 1 HEAD -- $1)~1 -- $(git diff --name-status $(git rev-list -n 1 HEAD -- $1)~1 | grep '^D' | cut -f 2); }; f'

Ho perso un file, cancellato per errore qualche commit fa?
Presto:

git restore my_deleted_file

La crisi è stata evitata.

Attenzione, con Git 2.23 (3 ° trimestre 2019) arriva il comando sperimentale chiamato git restore(!).
Quindi rinomina questo alias (come mostrato sotto).


Robert Dailey propone nei commenti il seguente alias:

restore-file = !git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "$1"

E Jegan aggiunge nei commenti :

Per impostare l'alias dalla riga di comando, ho usato questo comando:

git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\"" 

7
Ciò ripristina l'intero commit, non solo il file richiesto.
Daniel Bang,

5
Ecco il mio pseudonimo, funziona meravigliosamente:restore-file = !git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "$1"
void.pointer

1
@RobertDailey Sembra fantastico! Ho incluso il tuo alias nella risposta per una maggiore visibilità.
VonC

1
Per impostare l'alias dalla riga di comando, ho usato questo comando:git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\""
jegan

2
Expansion of alias 'restore' failed; '!git' is not a git command
Karl Morrison,

55

Se conosci il nome file, questo è un modo semplice con i comandi di base:

Elenca tutti i commit per quel file.

git log -- path/to/file

L'ultimo commit (più in alto) è quello che ha eliminato il file. Quindi è necessario ripristinare il secondo per ultimo commit.

git checkout {second to last commit} -- path/to/file

Ho appena usato questa soluzione e non è stato eseguito alcun commit per l'eliminazione. Sono stato in grado di ripristinare il file utilizzando l'id di commit più recente.
Adam,

Il commit successivo all'ultimo (commit precedente alla cancellazione) conterrebbe la versione più recente del file eliminato? Il penultimo (il commit prima del precedente commit alla cancellazione) potrebbe essere irrimediabilmente superato.
Suncat2000,

1
Questa è la prima soluzione che ho visto che è abbastanza semplice da non dover tornare qui per trovarla la prossima volta. Può essere.
Eloff

@ Suncat2000 "penultimo" significa "precedente commit per la cancellazione", uguale a "next to last". en.wiktionary.org/wiki/penultimate#Synonies
wisbucky

Grazie mille volte per questa risposta !!!!!
Rakesh Bk,

29

Per ripristinare un file eliminato e sottoposto a commit:

git reset HEAD some/path
git checkout -- some/path

È stato testato su Git versione 1.7.5.4.


1
Non ha funzionato per me. Dopo il checkout, mi sono error: pathspec 'foo' did not match any file(s) known to git.assicurato che il nome del file fosse corretto. Git versione 2.7.0
wisbucky

-1; questo è sbagliato. Questi comandi annulleranno una cancellazione che non è stata ancora impegnata (la prima mette in scena la cancellazione, se è stata messa in scena, e la seconda ignora le modifiche non messe in scena al file), ma qui stai sostenendo che ripristineranno una commit cancellazione del file, che semplicemente non è vero e fallirà con un errore come quello nel commento di @wisbucky sopra.
Mark Amery,

@MarkAmery In effetti, penso che questo comando abbia funzionato bene per quegli sviluppatori, che non hanno reso esplicita la gestione temporanea per il commit dei file rimossi git add -A, ma il file ripristinato era ancora in fase di non commit.
Fedir RYKHTIK,

25

Se hai apportato solo modifiche e cancellato un file, ma non lo hai eseguito, e ora hai interrotto le modifiche

git checkout -- .

ma i file eliminati non sono tornati, devi semplicemente eseguire il comando seguente:

git checkout <file_path>

E presto, il tuo file è tornato.


24

Ho questa soluzione .

  1. Ottieni l'ID del commit in cui il file è stato eliminato utilizzando uno dei modi seguenti.

    • git log --grep=*word*
    • git log -Sword
    • git log | grep --context=5 *word*
    • git log --stat | grep --context=5 *word* # consigliato se non ricordi quasi nulla
  2. Dovresti ottenere qualcosa del tipo:

commit bfe68bd117e1091c96d2976c99b3bcc8310bebe7 Autore: Alexander Orlov Data: gio 12 mag 23:44:27 2011 +0200

replaced deprecated GWT class
- gwtI18nKeySync.sh, an outdated (?, replaced by a Maven goal) I18n generation script

commit 3ea4e3af253ac6fd1691ff6bb89c964f54802302 Autore: Alexander Orlov Data: gio 12 maggio 22:10:22 2011 +0200

3 . Ora usando l'id commit bfe68bd117e1091c96d2976c99b3bcc8310bebe7 fai:

git checkout bfe68bd117e1091c96d2976c99b3bcc8310bebe7^1 yourDeletedFile.java

Poiché l'id commit fa riferimento al commit in cui il file era già stato eliminato, è necessario fare riferimento al commit appena prima di bfe68b che è possibile eseguire aggiungendo ^1. Questo significa: dammi il commit appena prima di bfe68b.


Questo è lo stesso approccio della risposta accettata, ma con alcuni altri modi per trovare il commit dell'eliminazione. Mi piace ancora l'approccio adottato nella risposta accettata, ma queste sono buone alternative. Grazie!
avdgaag

Presumo che prima il check out del file cancellato e poi (senza modificarlo) il commit non crea una copia del file. Giusto? (Devo farlo con le immagini e una copia renderebbe il repository più grande)
Stonecrusher


12

git undelete path/to/file.ext

  1. Inseriscilo nel tuo .bash_profile(o altro file pertinente che viene caricato quando apri una shell dei comandi):

    git config --global alias.undelete '!sh -c "git checkout $(git rev-list -n 1 HEAD -- $1)^ -- $1" -'
    
  2. Quindi utilizzare:

    git undelete path/to/file.ext
    

Questo alias controlla prima di tutto per trovare l'ultimo commit in cui si trovava questo file, quindi esegue un checkout Git del percorso di quel file dall'ultimo commit in cui si trovava questo file. Fonte .


11

In molti casi, può essere utile usare coreutils (grep, sed, ecc.) Insieme a Git. Conosco già abbastanza bene questi strumenti, ma Git meno. Se volessi fare una ricerca per un file cancellato, farei quanto segue:

git log --raw | grep -B 30 $'D\t.*deleted_file.c'

Quando trovo la revisione / il commit:

git checkout <rev>^ -- path/to/refound/deleted_file.c

Proprio come altri hanno affermato prima di me.

Il file verrà ora ripristinato allo stato precedente alla rimozione. Ricordati di reimpegnarlo nell'albero di lavoro se vuoi tenerlo in giro.


7

Ho dovuto ripristinare un mucchio di file eliminati da un commit specifico e l'ho gestito con due comandi:

git show <rev> --diff-filter=D --summary --name-only --no-commit-id | xargs git checkout <rev>^ -- 
git show <rev> --diff-filter=D --summary --name-only --no-commit-id | xargs git reset HEAD 

(Nota lo spazio finale alla fine di ogni comando.)

I file erano stati aggiunti al file .gitignore e quindi cancellati con git rm. Avevo bisogno di ripristinare i file, ma poi di metterli in scena. Avevo centinaia di file da ripristinare e digitare manualmente le cose per ciascun file come negli altri esempi sarebbe stato troppo lento.


7

In realtà, questa domanda riguarda direttamente Git, ma qualcuno come me lavora con strumenti GUI come WebStorm VCS oltre a conoscere i comandi Git CLI.

Faccio clic con il pulsante destro del mouse sul percorso che contiene il file eliminato, quindi vado su Git e quindi su Mostra cronologia .

Inserisci qui la descrizione dell'immagine

Gli strumenti VCS mostrano tutte le revisioni del treno e posso vedere tutti i commit e le modifiche di ciascuno di essi.

Inserisci qui la descrizione dell'immagine

Quindi seleziono i commit che il mio amico elimina il PostAd.jsfile. ora vedi sotto:

Inserisci qui la descrizione dell'immagine

E ora, posso vedere il mio file cancellato desiderio. Faccio semplicemente doppio clic sul nome del file e viene ripristinato.

Inserisci qui la descrizione dell'immagine

So che la mia risposta non è comandi Git, ma è veloce, affidabile e facile per sviluppatori principianti e professionisti. Gli strumenti di WebStorm VCS sono fantastici e perfetti per lavorare con Git e non hanno bisogno di altri plug-in o strumenti.


1
Questo è bellissimo! Grazie. Sicuramente una soluzione più semplice per coloro che usano uno degli IDE di JetBrains.
Fabiano Arruda,

Come ripristiniamo il file se è immagine?
Nodirabegimxonoyim,

Caro @FabianoArruda, gli IDE JetBrains sono potenti strumenti per lo sviluppo. grazie per il tuo bellissimo commento.
Amerllic,

Grazie a te caro @PeterMortensen per l'edizione.
Amerllic,

6

Ho avuto la stessa domanda. Senza saperlo, avevo creato un impegno penzolante .

Elenco di impegni sospesi

git fsck --lost-found

Ispezionare ogni commit penzolante

git reset --hard <commit id>

I miei file sono riapparsi quando sono passato al commit penzolante.

git status per il motivo:

“HEAD detached from <commit id where it detached>”


2
Grazie mille. Mi hai aiutato a ripristinare migliaia di righe di codici.
Reuben,

5
user@bsd:~/work/git$ rm slides.tex
user@bsd:~/work/git$ git pull 
Already up-to-date.
user@bsd:~/work/git$ ls slides.tex
ls: slides.tex: No such file or directory

Ripristina il file eliminato:

user@bsd:~/work/git$ git checkout
D       .slides.tex.swp
D       slides.tex
user@bsd:~/work/git$ git checkout slides.tex 
user@bsd:~/work/git$ ls slides.tex
slides.tex

2
La domanda riguardava il ripristino di un file dopo che è stato eliminato e la modifica è stata impegnata. Questa risposta riguarda il ripristino di un file che è stato rimosso solo nella directory di lavoro.
Akaihola,

È vero, ed era quello che stavo cercando.
Hola Soy Edu Feliz Navidad,

4

Se si conosce il commit che ha eliminato i file, eseguire questo comando dove si <SHA1_deletion>trova il commit che ha eliminato il file:

git diff --diff-filter=D --name-only <SHA1_deletion>~1 <SHA1_deletion> | xargs git checkout <SHA1_deletion>~1 --

La parte prima della pipe elenca tutti i file che sono stati eliminati nel commit; sono tutti checkout dal commit precedente per ripristinarli.


4

Trova il commit che ha eliminato il tuo file:

git log --diff-filter=D --oneline -- path/to/file | cut -f -d ' '

Uscita campione:

4711174

A partire da Git 2.23 esiste effettivamente un restorecomando. È ancora sperimentale ma per ripristinare qualcosa che hai rimosso in un commit (4711174 in questo caso) puoi quindi digitare:

git restore --source=4711174^ path/to/file

Nota ^ dopo l'ID commit in quanto vogliamo ripristinare qualcosa dal commit prima di quello che ha eliminato il file.

L' --sourceargomento dice al restorecomando dove cercare i file da ripristinare e può essere qualsiasi commit e persino l'indice.

Vedi: git-restore doc per git 2.23.0


4

Nel nostro caso abbiamo cancellato accidentalmente i file in un commit e alcuni commit in seguito ci siamo resi conto del nostro errore e volevamo recuperare tutti i file che erano stati eliminati, ma non quelli che erano stati modificati.

Sulla base dell'eccellente risposta di Charles Bailey, ecco il mio one-liner:

git co $(git rev-list -n 1 HEAD -- <file_path>)~1 -- $(git diff --name-status $(git rev-list -n 1 HEAD -- <file_path>)~1 head | grep '^D' | cut -f 2)

2

Semplice e preciso

Prima di tutto, ottieni un ultimo commit stabile in cui hai quel file per -

git log 

Di 'che trovi $ commitid 1234567 ..., quindi

git checkout <$commitid> $fileName

Ciò ripristinerà la versione del file che era in quel commit.


1

Per il modo migliore per farlo, provalo.


Innanzitutto, trova l'id di commit del commit che ha eliminato il tuo file. Ti fornirà un riepilogo dei commit quali file eliminati.

git log --diff-filter = D --summary

git checkout 84sdhfddbdddf ~ 1

Nota: 84sdhfddbdddè tuocommit id

Attraverso questo puoi facilmente recuperare tutti i file eliminati.


1

Potresti sempre git reverteseguire il commit che ha eliminato il file. ( Ciò presuppone che la cancellazione sia stata l'unica modifica nel commit. )

> git log
commit 2994bda49cd97ce49099953fc3f76f7d3c35d1d3
Author: Dave <dave@domain.com>
Date:   Thu May 9 11:11:06 2019 -0700

    deleted readme.md

E se hai continuato a lavorare e ti sei reso conto in seguito che non volevi impegnare quel commit di cancellazione, puoi ripristinarlo usando:

> git revert 2994bd

Ora git logmostra:

> git log
Author: Dave <dave@domain.com>
Date:   Thu May 9 11:17:41 2019 -0700

    Revert "deleted readme"

    This reverts commit 2994bda49cd97ce49099953fc3f76f7d3c35d1d3.

Ed readme.mdè stato ripristinato nel repository.


Poiché la domanda suppone che siano stati effettuati numerosi commit dopo l'eliminazione del file e poiché non vi è alcuna indicazione che i commit successivi siano indesiderati, ciò non sembra probabile che aiuti l'OP nella situazione descritta.
Jonathan Leffler

1
Sì! È possibile effettuare ulteriori commit e ripristinare comunque il commit di eliminazione. Quindi, se commit 111 elimina il file e commit 222, 333, 444, aggiunge / modifica cose, puoi ancora ripristinare il commit 111 per annullare l'eliminazione e diventerà commit 555
Dave Baghdanov

0

Ho anche questo problema utilizzando il codice seguente per recuperare un file precedente in una directory locale:

git checkout <file path with name>

L'esempio seguente funziona per me:

git checkout resources/views/usaSchools.blade.php



La cancellazione è già stata commessa. In questo caso è necessario specificare il commit da cui ripristinare.
sabato


-1

Se la cancellazione non è stata eseguita, il comando seguente ripristinerà il file eliminato nella struttura di lavoro.

$ git checkout -- <file>

È possibile ottenere un elenco di tutti i file eliminati nell'albero di lavoro utilizzando il comando seguente.

$ git ls-files --deleted

Se la cancellazione è stata commessa, trova il commit dove è avvenuta, quindi recupera il file da questo commit.

$ git rev-list -n 1 HEAD -- <file>
$ git checkout <commit>^ -- <file>

Nel caso in cui si stia cercando il percorso del file da ripristinare, il comando seguente visualizzerà un riepilogo di tutti i file eliminati.

$ git log --diff-filter=D --summary

-1

Per ripristinare tutti i file eliminati con Git, puoi anche fare:

git checkout $(git ls-files --deleted)

Dove git ls-files --deletedelenca tutti i file eliminati e git checkout $(git command)ripristina l'elenco dei file in un parametro.

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.