Finden Sie heraus, wann eine Datei in Git gelöscht wurde

1035

Ich habe ein Git-Repository mit n Commits.

Ich habe eine Datei, die ich brauche und die sich früher im Repository befand und die ich plötzlich suche und denke: "Oh! Wo ist diese Datei geblieben?"

Gibt es eine (Reihe von) Git-Befehlen, die mir sagen, dass "Datei wirklich_needed.txt bei Commit n-13 gelöscht wurde"?

Mit anderen Worten, ohne jedes einzelne Commit zu betrachten und zu wissen, dass mein Git-Repo jede Änderung jeder Datei enthält, kann ich schnell das letzte Commit finden, das diese Datei enthält, damit ich es zurückerhalten kann?

JohnMetta
quelle
5
Mögliches Duplikat von Wie finde ich eine gelöschte Datei im Commit-Verlauf?
Pedro Rolo
2
Der von Pedro geteilte Link hatte die Antwort auf meine Frage: Wie finde ich eine gelöschte Datei, wenn man sich nicht an den Pfad erinnert?
Gordon Bean

Antworten:

1127

git log --full-history -- [file path] Zeigt die Änderungen einer Datei an, funktioniert auch dann, wenn die Datei gelöscht wurde.

Beispiel:

git log --full-history  -- myfile

Wenn Sie nur das letzte Commit sehen möchten, bei dem eine Datei gelöscht wurde, verwenden Sie zusätzlich -1, z. git log --full-history -1 -- [file path]

Siehe Welches Commit hat eine Datei gelöscht?

Vogella
quelle
16
ist es möglich nach Mustern zu suchen? Ich habe den ganzen Namen der Datei vergessen = (vielleicht ist es möglich, ein Protokoll aller Löschungen zu bekommen?
wutzebaer
6
fand es hier: stackoverflow.com/questions/6017987/…
wutzebaer
6
Wenn Sie PowerShell verwenden, müssen die Bindestriche maskiert werden: git log '-' [Dateipfad]. Hoffentlich kann dies jemand anderem ein bisschen Zähneknirschen ermöglichen.
A. Wilson
68
Ich konnte suchen, indem ich git log -- */<<filename>>.<<file extension>>nicht den gesamten Dateipfad kannte.
Tom Howard
2
@MERose eckige Klammern dienen als Platzhalter für den realen Dateipfad.
Emile Bergeron
229

Kurze Antwort:

git log --full-history -- your_file

zeigt Ihnen alle Commits in der Geschichte Ihres Repos, einschließlich der berührten Merge-Commits your_file. Der letzte (oberste) hat die Datei gelöscht.

Einige Erklärungen:

Die --full-historyFlagge hier ist wichtig. Ohne diese Funktion führt Git eine "Vereinfachung des Verlaufs" durch, wenn Sie nach dem Protokoll einer Datei fragen. Die Dokumente enthalten nur wenige Details darüber, wie dies genau funktioniert, und mir fehlt der Mut, um es aus dem Quellcode herauszufinden, aber die Git-Log-Dokumente haben so viel zu sagen:

Standardmodus

Vereinfacht den Verlauf auf den einfachsten Verlauf und erklärt den Endzustand des Baums. Am einfachsten, weil einige Seitenzweige beschnitten werden, wenn das Endergebnis dasselbe ist (dh Zweige mit demselben Inhalt zusammenführen)

Dies betrifft natürlich, wann die Datei, deren Verlauf wir möchten, gelöscht wird , da der einfachste Verlauf, der den Endzustand einer gelöschten Datei erklärt, kein Verlauf ist . Besteht das Risiko, dass git logohne --full-historyeinfach behauptet wird, dass die Datei nie erstellt wurde? Leider ja. Hier ist eine Demonstration:

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

Beachten Sie, dass git log -- barim obigen Terminal-Dump buchstäblich keine Ausgabe ausgegeben wurde. Git "vereinfacht" die Geschichte zu einer Fiktion, in der es sie barnie gab. git log --full-history -- barAuf der anderen Seite erhalten wir das Commit, das erstellt wurde, barund das Commit, das es gelöscht hat.

Um es klar auszudrücken: Dieses Thema ist nicht nur theoretisch. Ich habe nur in die Dokumente geschaut und das --full-historyFlag entdeckt, weil git log -- some_filees für mich in einem echten Repository fehlgeschlagen ist, in dem ich versucht habe, eine gelöschte Datei aufzuspüren. Geschichte Vereinfachung könnte manchmal hilfreich sein , wenn Sie zu verstehen , sind versucht , wie eine derzeit bestehende Datei in seinem aktuellen Zustand sein kam, aber wenn Sie eine Datei auf die Spur zu versuchen Löschung es wahrscheinlicher ist , Sie versteckt schrauben über die verpflichten Sie kümmern sich um . Verwenden Sie --full-historyfür diesen Anwendungsfall immer das Flag.

Mark Amery
quelle
4
Beachten Sie, dass hierdurch nur der für den aktuellen Zweig relevante Verlauf durchsucht wird (nicht der gesamte Repo-Verlauf). Wenn die Datei im aktuellen Zweig noch nicht gelöscht wurde, sich jedoch in einem anderen Zweig befindet, wird das Lösch-Commit nicht gefunden. Sie müssen sich in einem Zweig befinden, in dem die Datei bereits gelöscht wurde . Vielleicht ist es offensichtlich, wenn ich darüber nachdenke, aber es hat mich zuerst erwischt.
Anentropic
1
Diese Antwort funktioniert. Aus der git logAusgabe selbst geht jedoch nicht hervor, dass das letzte Commit die Datei gelöscht hat . Ich habe es auch versucht git log --name-status --full-history -- file_nameund git log -p --stat --full-history -- file_name, aber keiner weist ausdrücklich darauf hin, dass die Datei beim letzten Festschreiben entfernt wurde. Dies scheint ein Fehler zu sein.
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 -- barenthält D barund A barfür mich in der Protokollausgabe mit Git 2.12.2. Sehen Sie diese Zeilen nicht in der Ausgabe? Welche Version hast du?
Mark Amery
git version 2.15.1Ja, Ihre Befehlssequenz meldet D barund A bar. Vielleicht ist mein Problem speziell auf den Verlauf meiner Datei zurückzuführen. Ich habe den Verlauf einer .htaccessDatei verfolgt, die gitignoreed und entfernt wurde. Ich habe das endlich herausgefunden und die Datei wieder hinzugefügt. Wenn ich --name-statusin den git logBefehl einbinde, werden zwei A .htaccessEinträge angezeigt (da ich sie beim letzten Festschreiben wieder hinzugefügt habe), aber nein D .htaccess. In einigen Fällen scheint git logein expliziter D file_nameEintrag nicht angezeigt zu werden, obwohl eine Datei aus dem Repository entfernt wurde .
Martin_W
@ Martin_ATS Neugierig. Ich frage mich, ob das vielleicht .htaccessin einem Commit X hinzugefügt wurde, aber dann nicht in dem Merge-Commit enthalten ist, das X auf den Master gebracht hat. Das ist das einzige , was ich mir vorstellen kann , dass ich möglicherweise könnte argumentieren , sollte wie eine Datei suchen hinzugefügt wurde und nie gelöscht und doch noch nicht vorhanden ist. Es wäre interessant zu versuchen, eine MCVE herauszufinden und dann herauszufinden, ob es sich um einen Git-Fehler handelt, und wenn nicht, ob es möglich ist, meine Antwort zu optimieren, um Ihren Fall zu behandeln.
Mark Amery
84

Git-Protokoll, aber Sie müssen dem Pfad ein Präfix voranstellen --

Z.B:

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 <[email protected]>
 Date:   Tue Jul 26 23:32:20 2011 -0500

 foo
Daniel
quelle
31

Ich habe hier gerade eine Lösung hinzugefügt (gibt es in git eine Möglichkeit, alle gelöschten Dateien im Repository aufzulisten ?) , Um die Commits gelöschter Dateien mithilfe eines regulären Ausdrucks zu ermitteln:

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

Dies gibt alles zurück, was in einem Verzeichnis mit dem Namen some_dir(Cascading) gelöscht wurde . Jeder sed regexp dort, wo es \/some_dir\/ist, wird tun.

OSX (danke an @triplee und @keif)

git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }
estani
quelle
1
Nett. Einige Unstimmigkeiten unter Bash in OS X:sed: 1: "/^commit/h;/\/some_dir\ ...": bad flag in substitute command: '}'
Brent Faust
@BrentFoust Es ist schade, dass ich das nicht testen kann ... versuchen Sie, am Ende ein Leerzeichen einzufügen (nach den Klammern, aber vor dem einfachen Anführungszeichen), die Manpage online ist darüber nicht klar ...
estani
Netter Vorschlag. Das Hinzufügen eines Leerzeichens vor dem einfachen Anführungszeichen hat jedoch nicht geholfen. Ein Leerzeichen vor der schließenden Klammer war ebenfalls nicht vorhanden.
Brent Faust
1
BSD / OSX sedist anscheinend nicht immer gut mit Semikolons als Befehlstrennzeichen. Versuchen Sie, sie in Zeilenumbrüche umzuwandeln, oder wechseln Sie zused -n -e '/^commit/h' -e '\:/some_dir/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }
Tripleee
1
Ich habe es getestet und git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }für mich unter OSX gearbeitet.
Keif
21

Sie finden das letzte Commit, das die Datei gelöscht hat, wie folgt:

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

Weitere Informationen finden Sie hier

Akif
quelle
11
Die primäre Upvoted-Lösung hat bei mir nicht funktioniert, aber diese hat funktioniert.
Nick Heiner
0

Versuchen:

git log --stat | grep file
Eric Woodruff
quelle