Naiver Ansatz ist find dir1 dir2 dir3 -type d -name .git | xargs -I {} dirname {}
, aber es ist zu langsam für mich, weil ich viele tiefe Ordnerstrukturen in Git-Repositories habe (zumindest denke ich, dass dies der Grund ist). Ich habe darüber gelesen, dass ich verhindern kann prune
, dass Find in Verzeichnisse zurückkehrt, sobald es etwas gefunden hat, aber es gibt zwei Dinge. Ich bin mir nicht sicher, wie das funktioniert (ich meine, ich verstehe nicht, was prune
funktioniert, obwohl ich die Manpage gelesen habe) und das zweite würde in meinem Fall nicht funktionieren, weil es verhindern würde, dass find
es in einen .git
Ordner zurückkehrt, aber nicht in alle andere Ordner.
Was ich also wirklich brauche, ist:
Überprüfen Sie für alle Unterverzeichnisse, ob sie einen .git
Ordner enthalten, und beenden Sie die Suche in diesem Dateisystemzweig und melden Sie das Ergebnis. Es wäre perfekt, wenn dies auch versteckte Verzeichnisse von der Suche ausschließen würde.
getpof .git
ist was ich benutze. github.com/thrig/scripts/blob/master/filesys/getpof.cAntworten:
Okay, ich bin mir immer noch nicht ganz sicher, wie das funktioniert, aber ich habe es getestet und es funktioniert.
Ich freue mich darauf, dasselbe schneller zu machen.
quelle
-prune
geht's: Sie beginnen an der Wurzel eines Baumes und bewegen sich nach unten. Wenn eine bestimmte Bedingung zutrifft, schneiden Sie einen ganzen Teilbaum aus (wie echtes "Beschneiden"), sodass Sie keine Knoten mehr in diesem Teilbaum betrachten .-type d
nach der Bedingungtest -e ...
, und wenn dies der Fall ist, führen wir Aktionen aus-print -prune
, dh drucken sie aus und schneiden den Teilbaum aus, oder?find . -type d -exec test -e '{}/.git' \; -print -prune | parallel cd "{}" \&\& git pull --rebase
GNUparallel
ist ein sehr praktischer Ersatz fürxargs
Mögliche Lösung
Für GNU
find
und andere Implementierungen, die Folgendes unterstützen-execdir
:(siehe die Kommentare)
Zuvor besprochenes Zeug
Lösung, wenn das Beschneiden unten
.git
ausreichtWenn
-printf '%h'
unterstützt wird (wie im Fall von GNUsfind
), brauchen wir nichtdirname
:Sobald es auf einen Ordner
.git
im aktuellen Pfad stößt, gibt es ihn aus und hört auf, weiter unten im Teilbaum zu suchen.Lösung, wenn der gesamte Ordnerbaum entfernt werden soll, sobald a
.git
gefunden wurdeVerwenden,
-quit
wenn Ihr esfind
unterstützt:(Nach diesem ausführlichen Beitrag von Stéphane wird Chazelas
-quit
in GNUs und FreeBSDsfind
sowie in NetBSDs als unterstützt-exit
.)Wieder mit
-printf '%h'
wenn unterstützt:Lösung zum Beschneiden auf derselben Ebene wie der
.git
OrdnerIm Abschnitt "Mögliche Lösung" finden Sie die aktuelle Lösung für dieses spezielle Problem.
(Oh, und offensichtlich gehen die verwendeten Lösungen
xargs
davon aus, dass die Pfade keine Zeilenumbrüche enthalten, da Sie sonst Null-Byte-Magie benötigen würden.)quelle
dir1
zwei Verzeichnisse enthältdirx
unddiry
jedes ein.git
Verzeichnis enthält, meldet dies nurdirx/.git
dir1/.git
, dass sie, falls vorhanden, immer noch abfälltdir1/dirx
, was nach meiner Lektüre der OP-Anforderungen nicht erwünscht istIdealerweise möchten Sie Verzeichnisbäume nach Verzeichnissen
.git
durchsuchen , die einen Eintrag enthalten, und die Suche weiter unten beenden (vorausgesetzt, Sie haben keine weiteren Git-Repos in Git-Repos).Das Problem ist, dass bei
find
dieser Art der Überprüfung (dass ein Verzeichnis einen.git
Eintrag enthält ) bei Standard ein Prozess erzeugt wird, der eintest
Dienstprogramm unter Verwendung des-exec
Prädikats ausführt , was weniger effizient ist als das Auflisten des Inhalts einiger Verzeichnisse.Eine Ausnahme wäre, wenn Sie die
find
integriertebosh
Shell verwenden (eine von @schily entwickelte POSIXified- Verzweigung der Bourne-Shell ), die ein-call
Prädikat zum Auswerten von Code in der Shell enthält, ohne einen neuen sh-Interpreter erzeugen zu müssen:Oder nutzen Sie
perl
‚sFile::Find
:Länger, aber schneller als
zsh
'sprintf '%s\n' **/.git(:h)
(das in alle nicht versteckten Verzeichnisse absteigt) oder GNUsfind
,find . -name '.?*' -prune -o -type d -exec test -e '{}/.git' \; -prune -print
die einentest
Befehl in einem neuen Prozess für jedes nicht versteckte Verzeichnis ausführen.quelle
.git
dies auch eine Datei sein kann - viagit worktree
-d
s in geändert-e
.Wenn Sie find verwenden, können Sie Verzeichnisse finden mit:
Die Ergebnisliste ist schnell und die weitere Verarbeitung ist ebenfalls einfach.
quelle
locate '*/.git'
sollte genug sein.Verwenden
time
dies, um den Unterschied mit und ohne zu sehen-prune
.Dies basiert auf einer Lösung in der
man find
. Sie können dasCVS
und,svn
falls nicht erforderlich, bearbeiten . Manpage-Inhalt folgtFühren Sie anhand des folgenden Projektverzeichnisses und der zugehörigen SCM-Verwaltungsverzeichnisse eine effiziente Suche nach den Wurzeln der Projekte durch:
In diesem Beispiel wird ein
-prune
unnötiger Abstieg in bereits erkannte Verzeichnisse verhindert (z. B. suchen wir nichtproject3/src
, weil wir bereits gefunden habenproject3/.svn
), sondern es wird sichergestellt, dass Geschwisterverzeichnisse (project2
undproject3
) gefunden werden.quelle