Wie finde ich eine gelöschte Datei in einem Git-Repository und stelle sie wieder her?

Lesezeit: 10 Minuten

Benutzer-Avatar
Avdgaag

Angenommen, ich bin in einem Git-Repository. Ich lösche eine Datei und übertrage diese Änderung. Ich arbeite weiter und mache weitere Commits. Dann entdecke ich, dass ich diese Datei nach dem Löschen wiederherstellen muss.

Ich weiß, dass ich eine Datei mit auschecken kann git checkout <commit> -- filename.txtaber ich weiß nicht, wann diese Datei gelöscht wurde.

  1. Wie finde ich den Commit, der einen bestimmten Dateinamen gelöscht hat?
  2. Wie stelle ich diese Datei wieder in meiner Arbeitskopie wieder her?

  • Beachten Sie, dass der vorherige Kommentar die Frage im Titel beantwortet, nicht im Hauptteil – das schließt das Herausfinden ein Wenn die Datei wurde gelöscht.

    – durchschn

    16. Dezember 2011 um 16:02 Uhr

  • Um den Commit zu finden, wurde eine Datei gelöscht in: git log --diff-filter=D -- path/to/file

    – Titanköder

    16. März 2012 um 21:28 Uhr

  • Verwandte: Wie verwerfen Sie nicht bereitgestellte Änderungen in Git?.

    Benutzer456814

    28. April 2014 um 5:16 Uhr

  • Verwandte: So finden Sie eine gelöschte Datei im Commit-Verlauf

    – Owen Blacker

    3. November 2014 um 14:14 Uhr


  • @hhh git checkout deletedFile wird wiederhergestellt deletedFile wenn es gelöscht wurde, aber diese Löschung wurde noch nicht inszeniert oder begangen. Das ist nicht das, wonach die Frage hier fragt; Bei dieser Frage geht es darum, wie eine Datei wiederhergestellt wird, deren Löschung vor vielen Commits festgeschrieben wurde.

    – Mark Amery

    15. April 2017 um 10:33 Uhr

Benutzer-Avatar
CB Bailey

Finden Sie den letzten Commit, der den angegebenen Pfad beeinflusst hat. Da sich die Datei nicht im HEAD-Commit befindet, muss sie bei diesem vorherigen Commit gelöscht worden sein.

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

Checken Sie dann die Version beim Commit vorher aus, indem Sie das Caretzeichen (^) Symbol:

git checkout <deleting_commit>^ -- <file_path>

Oder in einem Befehl, wenn $file ist die betreffende Datei.

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

Wenn Sie zsh verwenden und die Option EXTENDED_GLOB aktiviert haben, funktioniert das Caret-Symbol nicht. Sie können verwenden ~1 stattdessen.

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

  • Der schwierige Teil besteht darin, den Commit VORHER auszuchecken, indem Sie das ^-Suffix verwenden. Vielen Dank.

    – Christian Ouard

    26. April 2010 um 14:40 Uhr

  • Aus irgendeinem Grund funktioniert dies nicht in zsh. ± git checkout $(git rev-list -n 1 HEAD "spec/Sporkfile_example.rb")^ -- "spec/Sporkfile_example.rb" zsh: no matches found: b71c152d8f38dcd23ad7600a93f261a7252c59e9^ Ich bin auf Bash umgestiegen und es hat gut funktioniert.

    – Zora

    28. Februar 2012 um 3:45 Uhr


  • Von der Windows-Befehlszeile bekam ich einen Fehler. error: pathspec <filename> did not match any file(s) known to git.. Die Lösung war die Verwendung von git bash.

    – donturner

    26. Juli 2012 um 18:07 Uhr

  • @zoras zsh hat eine eigene Erweiterung für ‚^‘, glaube ich, aber Sie können die alternative Syntax von ‚~1‘ verwenden: git checkout <deleting-commit>~1 -- <file-path> ~X ermöglicht es Ihnen, X Commits vor dem angegebenen Commit anzugeben, also ist ~1 der Commit davor, ~2 sind zwei Commits davor usw

    – Nils Luxton

    10. September 2012 um 15:07 Uhr


  • An der Windows-Cmd-Eingabeaufforderung wird die ^ Zeichen ist das Fluchtzeichen! Daher müssen Sie bei cmd eingeben ^^ um cmd mitzuteilen, dass Sie ein einzelnes Literal ^ wollen und dass Sie danach nichts anderes mehr maskieren. Was vielen Menschen passiert ist, dass die ^ gefolgt von einem Leerzeichen. cmd denkt also, dass Sie das Leerzeichen maskieren – was einfach ein Leerzeichen ergibt. Bis Git also die cli-Argumente erhält, sieht es SHA1 und nicht SHA1^. Es ist wirklich nervig. ~ ist kein Fluchtzeichen, deshalb funktioniert das immer noch. (PS. Wenn Sie glauben, dass Googler diese Informationen möchten, stimmen Sie bitte diesem Kommentar zu.)

    – Alexander Vogel

    18. September 2015 um 14:48 Uhr

Benutzer-Avatar
Robert Munteanu

  1. Holen Sie sich alle Commits, die Dateien gelöscht haben, sowie die Dateien, die gelöscht wurden:

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

    Notieren Sie sich den gewünschten Commit-Hash, z e4e6d4d5e5c59c69f3bd7be2.

  2. Stellen Sie die gelöschte Datei von einem vorherigen Commit wieder her (~1) auf das oben festgelegte Commit (e4e6d4d5e5c59c69f3bd7be2):

    git checkout e4e6d4d5e5c59c69f3bd7be2~1 path/to/file.ext
    

    Beachten Sie das ~1.

  • neugierig, worauf bezieht sich die ~1?

    – Tommy Chheng

    22. Juli 2011 um 17:41 Uhr

  • @tommy – die Tilde-Spezifikation gibt Ihnen das n-te Enkelkind des benannten Commits . Sehen book.git-scm.com/4_git_treeishes.html für mehr Details .

    – Robert Munteanu

    23. Juli 2011 um 12:00 Uhr

  • Dies ist bei weitem der einfachste und intuitivste Ansatz. git log -- *PartOfMyFileName*. Danke für $commit~1

    – bgs

    10. April 2013 um 23:25 Uhr

  • das git checkout $commit~1 filename Syntax funktioniert perfekt für einzelne Dateien und funktioniert auch für ganze Verzeichnisse. dh: um alle gelöschten Bilder in ./images von sha 12345 wiederherzustellen: git checkout 12345~1 images. danke für diese antwort!

    – keine Eingabe

    3. Juni 2014 um 4:59 Uhr

  • @Alexar $commit~1 bedeutet, dass Sie den Namen des Commits hinzufügen sollten. Etwas wie 1d0c9ef6eb4e39488490543570c31c2ff594426c wo $commit ist.

    – Eugen

    7. April 2015 um 6:27 Uhr

Benutzer-Avatar
Manu

So stellen Sie alle gelöschten Dateien in einem Ordner wieder her:

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

  • Wohin werden die Dateien geleitet? Ich sehe keine Veränderung.

    – Wilhelm Groß

    13. September 2013 um 14:36 ​​Uhr

  • Dies ist wahrscheinlich die einfachste Methode. Es ist pervers, wie schwierig git hat selbst die einfachste Aufgabe gemacht.

    – jww

    19. Oktober 2013 um 4:12 Uhr

  • Das ls-files Unterbefehl ist praktisch, scheint aber nicht für Dateien zu funktionieren, die mit entfernt wurden git rm dh inszeniert, geschweige denn begangen, was das OP gefragt hat.

    – MarkHu

    17. November 2017 um 8:47 Uhr

  • @RomainValeri – Es ist 2019. Die Tools funktionieren für mich. Ich arbeite nicht für die Tools. Wenn Lernen erforderlich ist, ist das Design gebrochen.

    – jww

    5. Dezember 2019 um 10:24 Uhr


  • @RomainValeri, @jww ihr habt beide Recht. git ist nahezu beispiellos in seiner Nützlichkeit, während es auch unglaublich kompliziert zu lernen ist. Ein nennenswerter Anteil an gits Lernkurve ist auf eine inkonsistente / nicht intuitive Benutzeroberfläche zurückzuführen. Wenn ich etwas Schwieriges lerne, gibt es mir persönlich unter anderem Sicherheit, wenn ich sehe, dass andere (kompetente) Menschen ebenfalls Schwierigkeiten haben, es zu verstehen

    – Matthäus Strasiotto

    17. März 2021 um 23:21 Uhr

Benutzer-Avatar
Brett

Wenn Sie eine Datei gelöscht haben, die in der neuesten Datei vorhanden ist HEAD committen, können Sie es wiederherstellen mit:

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

Benutzer-Avatar
Josh Lee

Wenn Sie verrückt sind, verwenden Sie git-bisect. Folgendes ist zu tun:

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

Jetzt ist es an der Zeit, den automatisierten Test auszuführen. Der Shell-Befehl '[ -e foo.bar ]' wird 0 zurückgeben, wenn foo.bar existiert, und 1 sonst. Der “Run”-Befehl von git-bisect verwendet eine binäre Suche, um automatisch den ersten Commit zu finden, bei dem der Test fehlschlägt. Es beginnt auf halbem Weg durch den angegebenen Bereich (von gut bis schlecht) und halbiert ihn basierend auf dem Ergebnis des angegebenen Tests.

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

Jetzt sind Sie bei dem Commit, der es gelöscht hat. Von hier aus können Sie zurück in die Zukunft springen und verwenden git-revert um die Änderung rückgängig zu machen,

git bisect reset
git revert <the offending commit>

oder Sie könnten einen Commit zurückgehen und den Schaden manuell untersuchen:

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

  • Könnten Sie das näher erläutern git bisect run '[ -e foo.bar ]'?

    – durchschn

    4. Juni 2009 um 22:53 Uhr

  • Sie können gut und schlecht auch manuell verwenden, wenn es etwas ist, das nicht automatisch überprüft werden kann. Siehe die Bisect-Manpage.

    – Josh Lee

    4. Juni 2009 um 23:00 Uhr

  • @avdgaag die git bisect run weist Git an, die Halbierung zu automatisieren, indem der Befehl nach dem Wort „run“ ausgeführt wird, wo der Befehl zurückkehren muss 0 Für ein good Fassung (vgl git help bisect für Details). Das '[ -e foo.bar ]' ist ein Standardausdruck zum Testen von if-Dateien foo.bar existiert (die Implementierung befindet sich normalerweise in einer Datei /usr/bin/[ which is usually hardlinked to /usr/bin/test) and the single quation marks are used to put that all as a single command line argument.

    – Mikko Rantalainen

    Mar 18, 2013 at 7:18

  • Great idea. I tried this approach and it identified a commit prior to deletion, but not the commit that actually deleted the file. And in another test it identified 2 commits prior to the deletion.

    – Michael Osofsky

    May 22, 2019 at 19:48

  • Insane? Maybe. But bisect is a great way to help find where a bug was introduced and so it’s a valuable skill to learn anyway. So although maybe not the ‘correct’ or most ‘correct’ way here it’s still a good idea and worth a +1 definitely!

    – Pryftan

    Nov 12, 2019 at 12:08

My new favorite alias, based on bonyiii’s answer (upvoted), and my own answer about “Pass an argument to a Git alias command”:

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'

I have lost a file, deleted by mistake a few commits ago?
Quick:

git restore my_deleted_file

Crisis averted.

Warning, with Git 2.23 (Q3 2019) comes the experimental command named git restore(!).
So rename this alias (as shown below).


Robert Dailey proposes in the comments the following alias:

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

And jegan adds in the comments:

For setting the alias from the command line, I used this command:

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

  • Could you elaborate on git bisect run '[ -e foo.bar ]'?

    – durchschn

    4. Juni 2009 um 22:53 Uhr

  • Sie können gut und schlecht auch manuell verwenden, wenn es etwas ist, das nicht automatisch überprüft werden kann. Siehe die Bisect-Manpage.

    – Josh Lee

    4. Juni 2009 um 23:00 Uhr

  • @avdgaag die git bisect run weist Git an, die Halbierung zu automatisieren, indem der Befehl nach dem Wort „run“ ausgeführt wird, wo der Befehl zurückkehren muss 0 Für ein good Fassung (vgl git help bisect für Details). Das '[ -e foo.bar ]' ist ein Standardausdruck zum Testen von if-Dateien foo.bar existiert (die Implementierung befindet sich normalerweise in einer Datei /usr/bin/[ which is usually hardlinked to /usr/bin/test) and the single quation marks are used to put that all as a single command line argument.

    – Mikko Rantalainen

    Mar 18, 2013 at 7:18

  • Great idea. I tried this approach and it identified a commit prior to deletion, but not the commit that actually deleted the file. And in another test it identified 2 commits prior to the deletion.

    – Michael Osofsky

    May 22, 2019 at 19:48

  • Insane? Maybe. But bisect is a great way to help find where a bug was introduced and so it’s a valuable skill to learn anyway. So although maybe not the ‘correct’ or most ‘correct’ way here it’s still a good idea and worth a +1 definitely!

    – Pryftan

    Nov 12, 2019 at 12:08

user avatar
Mark Amery

If you know the filename, this is an easy way with basic commands:

List all the commits for that file.

git log -- path/to/file

The last commit (topmost) is the one that deleted the file. So you need to restore the second to last commit.

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

  • This is the first solution I’ve seen that’s simple enough that I won’t have to come back here to find it next time. Maybe.

    – Eloff

    Apr 3, 2018 at 21:44

  • @Suncat2000 “second to last” means “previous commit to the deletion”, same as “next to last”. en.wiktionary.org/wiki/penultimate#Synonyms

    – wisbucky

    May 15, 2018 at 18:41

1331050cookie-checkWie finde ich eine gelöschte Datei in einem Git-Repository und stelle sie wieder her?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy