Sagen Sie einfach, ich habe eine Datei: "HelloWorld.pm" in mehreren Unterverzeichnissen innerhalb eines Git-Repositorys.
Ich möchte einen Befehl ausgeben, um die vollständigen Pfade aller Dateien zu finden, die mit "HelloWorld.pm" übereinstimmen:
Zum Beispiel:
/path/to/repository/HelloWorld.pm
/path/to/repository/but/much/deeper/down/HelloWorld.pm
/path/to/repository/please/dont/make/me/search/through/the/lot/HelloWorld.pm
Wie kann ich Git verwenden, um alle vollständigen Pfade, die einem bestimmten Dateinamen entsprechen, effizient zu finden?
Mir ist klar, dass ich dies mit dem Linux / Unix-Befehl find tun kann, aber ich hatte gehofft, nicht alle Unterverzeichnisse nach Instanzen des Dateinamens durchsuchen zu müssen.
git ls-files 'HelloWorld.pm' '*/HelloWorld.pm'
Hmm, die ursprüngliche Frage betraf das Repository. Ein Repository enthält mehr als 1 Commit (zumindest im allgemeinen Fall), aber die vor der Suche gegebenen Antworten durchsuchen nur ein Commit.
Da ich keine Antwort finden konnte, die wirklich den gesamten Commit-Verlauf durchsucht, habe ich ein schnelles Brute-Force-Skript geschrieben, das (fast) alle Commits berücksichtigt.
Vielleicht gibt es einen eleganteren Weg.
Bitte beachten Sie die triviale Art und Weise, wie der Parameter an grep übergeben wird, damit er mit Teilen des Dateinamens übereinstimmt. Wenn dies nicht erwünscht ist, verankern Sie Ihren Suchausdruck und / oder fügen Sie geeignete Grep-Optionen hinzu.
Für tiefe Historien könnte die Ausgabe zu verrauscht sein. Ich dachte an ein Skript, das eine Liste von Revisionen in einen Bereich konvertiert, wie das Gegenteil von dem, was Git Rev-List tun kann. Aber bisher ist es ein Gedanke geblieben.
quelle
git rev-list --all | xargs -I '{}' git ls-tree --full-tree -r '{}' | grep '.*HelloWorld\.pm$'
. Dies löst auch das Problem der Festplattenüberflutung.Versuchen:
quelle
git ls-tree -r HEAD | findstr HelloWorld.pm
man git ls-tree
zeigt, dass dies-r
bedeutet "In Unterbäume zurückgreifen". Ich weiß nicht was das bedeutet. Können Sie bitte erklären, was dies bedeutet?grep
, Ausführen von Bash-Skripten usw., sodass diese Antwort einwandfrei funktionieren sollte wie es ist. Probieren Sie es aus und lassen Sie es mich wissen. Ich habe Windows für Ubuntu vor ein paar Jahren komplett über Bord geworfen.-r
sollte der Befehl ls-tree veranlassen, Unterverzeichnisse im Repository zu durchsuchen.Das grep -i macht die Groß- und Kleinschreibung von grep unabhängig.
quelle
[Ich gebe zu, es ist ein bisschen Kommentarmissbrauch, aber ich kann noch keinen Kommentar abgeben und dachte, ich würde die Antwort von @ uwe-geuder verbessern.]
Nochmals +1 an @ uwe-geuder für eine großartige Antwort.
Wenn Sie sich für die BASH selbst interessieren:
Sofern Ihnen die Wortaufteilung in einer for-Schleife nicht garantiert ist (wie bei Verwendung eines Arrays wie diesem :)
for item in "${array[@]}"
, empfehle ich dringend,while IFS= read var ; do ... ; done < <(command)
die Befehlsausgabe zu verwenden, wenn die Schleife durch Zeilenumbrüche getrennt ist (oderread -d''
wenn die Ausgabe durch die Zeile getrennt ist) Nullzeichenfolge$'\0'
). Obwohlgit rev-list --all
garantiert 40-Byte-Hexadezimalzeichenfolgen (ohne Leerzeichen) verwendet werden, gehe ich nie gerne Risiken ein. Ich kann den Befehl jetzt einfach vongit rev-list --all
jedem Befehl ändern, der Zeilen erzeugtIch empfehle auch die Verwendung integrierter BASH-Mechanismen zum Einfügen von Eingaben und Filtern von Ausgaben anstelle von temporären Dateien.
quelle
git rev-list --all | while read rev; do; git ls-tree --full-tree -r $rev | cut -c54- | fgrep -- "$name"; done | sort -u
$rev
zu zeigen, in welchen Revisionen es gefunden wurde.Das Skript von Uwe Geuder (@ uwe-geuder) ist großartig, aber es ist wirklich nicht nötig, jede der ls-tree-Ausgaben ungefiltert in einem eigenen Verzeichnis abzulegen.
Viel schneller und mit weniger Speicherplatz: Führen Sie das grep für die Ausgabe aus und speichern Sie es dann, wie in dieser Übersicht gezeigt
quelle
# How to find a long-lost file by searching all commits
und 2) den Code aus dem Kern, der direkt in diese Antwort eingefügt wurde.