Fügen Sie rekursiv Dateien nach Muster hinzu

172

Wie füge ich rekursiv Dateien nach einem Muster (oder Glob) hinzu, das sich in verschiedenen Verzeichnissen befindet?

Zum Beispiel möchte ich A/B/C/foo.javaund D/E/F/bar.java(und mehrere andere Java-Dateien) mit einem Befehl hinzufügen :

git add '*.java'

Leider funktioniert das nicht wie erwartet.

Michel Krämer
quelle
2
Es funktioniert für mich (Mac OS X, Git 1.7.1+). Welches Betriebssystem und welche Git-Version verwenden Sie?
Chris Johnsen
3
Wenn Sie einige (bereits verfolgte) .javaDateien in Ihrem aktuellen Verzeichnis haben, stoßen Sie möglicherweise auf die komplizierte Platzhalterbehandlung zwischen bash und dem msys-Befehlszeilen-Helfer . Ich bin mir nicht sicher über eine Lösung. Sie können mehrere Anführungszeichen-Ebenen ausprobieren: git add '"*.java"'(Die einfachen Anführungszeichen werden von bash verwendet , um die Glob-Erweiterung zu verhindern. Die doppelten Anführungszeichen werden von der msys-Ebene verwendet, um die Glob-Erweiterung zu verhindern.)
Chris Johnsen
1
Danke für den Hinweis. Das funktioniert leider auch nicht. Sie sagen, das wurde behoben, aber ich habe bereits die neueste Version.
Michel Krämer
1
git add *.javafunktioniert für mich (auf Powershell mit GitHub Client)
ThaDafinser

Antworten:

88

Die Antwort von Sergio Acosta ist wahrscheinlich die beste Wahl, wenn einige der hinzuzufügenden Dateien möglicherweise noch nicht nachverfolgt wurden. Wenn Sie sich auf Dateien beschränken möchten, die git bereits kennt, können Sie sie git-ls-filesmit einem Filter kombinieren :

git ls-files [path] | grep '\.java$' | xargs git add

Git bietet keine ausgefallenen Mechanismen, um dies selbst zu tun, da es sich im Grunde um ein Shell-Problem handelt: Wie erhält man eine Liste von Dateien, die als Argumente für einen bestimmten Befehl bereitgestellt werden sollen?

Cascabel
quelle
8
Vielen Dank! Ich habe Ihr Kommando leicht verbessert und jetzt macht es das, wonach ich gesucht habe:git ls-files -co --exclude-standard | grep '\.java$' | xargs git add
Michel Krämer
169

Sie können git add [path]/\*.javaJava-Dateien aus Unterverzeichnissen hinzufügen,
z git add ./\*.java. B. für das aktuelle Verzeichnis.

Aus der git addDokumentation :

Fügt Inhalte aus allen *.txtDateien im DocumentationVerzeichnis und seinen Unterverzeichnissen hinzu:

$ git add Documentation/\*.txt

Beachten Sie, dass das Sternchen *in diesem Beispiel aus der Shell zitiert wird. Dadurch kann der Befehl die Dateien aus den Unterverzeichnissen des Documentation/Verzeichnisses einschließen .

Sergey Glotov
quelle
2
@ MichelKrämer war es wahrscheinlich nicht, aber es ist jetzt.
Alberto
7
Dies ist die beste Lösung, funktioniert auch unter Windows.
TheTFo
1
"Sternchen * wird aus der Shell zitiert". Ich denke du meinst "entkommen". In jedem Fall verhindert der Backslash, dass die Shell sie erweitert.
Widman
1
@gwideman Ich denke du hast recht, aber ich bin es nicht. Es ist ein Zitat aus den Dokumenten git-scm.com/docs/git-add#_examples
Sergey Glotov
62

Mit zsh Sie laufen:

git add "**/*.java"

und alle Ihre *.javaDateien werden rekursiv hinzugefügt.

Olivier Verdier
quelle
Danke dafür, aber ich arbeite mit msysgit unter Windows und es gibt nur eine Bash.
Michel Krämer
1
Nun, ich sehe, dass es eine zshShell für Fenster gibt ... Sie werden sich einen Gefallen tun, wenn Sie sie anstelle von Bash verwenden, imho.
Olivier Verdier
1
Der Windows-Port von zsh basiert auf einer sehr alten Version und stürzt ständig ab (zum Beispiel wenn ich eintrete ls).
Michel Krämer
Wow, perfekt. Ich wusste nichts über diese Funktion!
Tomáš Votruba
1
Das hat nichts mit zsh zu tun. Ich denke, diese Antwort verfehlt den Punkt, an dem Sie den Pfad mit intakten Platzhaltern an git übergeben und von git verarbeiten lassen möchten. Sie möchten daher verhindern, dass die von Ihnen verwendete Shell die Platzhalter erweitert. Dazu müssen Sie es auf eine Weise zitieren, die für die von Ihnen verwendete Shell geeignet ist. Siehe andere Antworten für Details.
Gwideman
55

Ein bisschen abseits des Themas (nicht speziell mit Git verbunden), aber wenn Sie unter Linux / Unix arbeiten, könnte eine Problemumgehung sein:

find . -name '*.java' | xargs git add

Und wenn Sie Pfade mit Leerzeichen erwarten:

find . -name '*.java' -print0 | xargs -0 git add

Aber ich weiß, dass Sie nicht genau danach gefragt haben.

Sergio Acosta
quelle
6
Kleines Problem bei diesem Ansatz - Wenn Sie eine Datei "finden", die mit Ihrem .gitignore übereinstimmt, beschwert sich git, dass Sie versuchen, eine Datei hinzuzufügen, die Sie ignorieren sollen.
Yooy
2
@yoyo - Ich habe gerade -f am Ende hinzugefügt, und das hat das behoben
Maslow
5
@Maslow, das wird die Datei zwangsweise hinzufügen, obwohl sie ignoriert werden sollte (basierend auf .gitignore). Ich würde es vorziehen, die Beschwerde zu erhalten und die Datei nicht hinzuzufügen (was das Standardverhalten ist)
yoyo
Wie ist das in irgendeiner Weise besser, als git die Wildcard-Erweiterung durchführen zu lassen?
Widman
12

Sergeys Antwort (nicht gutschreiben) funktioniert:

You can use git add [path]/\*.java

mit einem neuen git:

$git version
git version 1.7.3.4

Dateien für den Test:

$find -name .git -prune -o -type f -print | sort
./dirA/dirA-1/dirA-1-1/file1.txt
./dirA/dirA-1/dirA-1-2/file2.html
./dirA/dirA-1/dirA-1-2/file3.txt
./dirA/dirA-1/file4.txt
./dirB/dirB-1/dirB-1-1/file5.html
./dirB/dirB-1/dirB-1-1/file6.txt
./file7.txt

Git-Status:

$git status -s
?? dirA/
?? dirB/
?? file7.txt

Hinzufügen von * .txt:

$git add \*.txt

Aktualisierter Status:

$git status -s
A  dirA/dirA-1/dirA-1-1/file1.txt
A  dirA/dirA-1/dirA-1-2/file3.txt
A  dirA/dirA-1/file4.txt
A  dirB/dirB-1/dirB-1-1/file6.txt
A  file7.txt
?? dirA/dirA-1/dirA-1-2/file2.html
?? dirB/dirB-1/dirB-1-1/file5.html
Alberto
quelle
8

Wenn Sie Ihre Dateien bereits verfolgen und Änderungen daran vorgenommen haben und sie nun anhand eines Musters selektiv hinzufügen möchten, können Sie das --modifiedFlag verwenden

git ls-files --modified | grep '<pattern>' | xargs git add

Wenn Sie beispielsweise nur die CSS-Änderungen zu diesem Commit hinzufügen möchten, können Sie dies tun

git ls-files --modified | grep '\.css$' | xargs git add

Sehen Sie man git-ls-filesfür mehr Flaggen

RAM
quelle
5

Einfach benutzen git add *\*.java. Dadurch werden alle Java-Dateien im Stammverzeichnis und in allen Unterverzeichnissen hinzugefügt.

Jan Lovstrand
quelle
Gute Antwort. Ich habe git add * / pom.xml, um alle Dateinamen pom.xml hinzuzufügen.
Philip Rego
4

Hinzufügen einer Windows-Befehlszeilenlösung, die noch nicht erwähnt wurde:

for /f "delims=" %G in ('dir /b/s *.java') do @git add %G
Selalerer
quelle
3

Ich wollte nur Dateien hinzufügen, die eine bestimmte Zeichenfolge hatten, basierend auf git status:

git status | grep string | xargs git add

und konnte dann git commit -m 'commit msgalle geänderten Dateien mit "string" im Titel der Datei festschreiben

Bdanin
quelle
2

Wie unter " Git: Wie füge ich rekursiv alle Dateien in einem Verzeichnis-Teilbaum hinzu, die einem Glob-Muster entsprechen? " Erwähnt, wenn '*.java'ja, lassen Sie Ihr Pathspec-Globbing (wie ) richtig maskieren oder zitieren , dann ja, Git hinzufügen'*.java'

Git 2.13 (Q2 2017) verbessert das für interaktives Hinzufügen:

Siehe Commit 7288e12 (14. März 2017) von Jeff King ( peff) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit 153e0d7 , 17. März 2017)

add --interactive: Erweitern Sie pathspecs nicht mit ls-files

Wenn wir die Liste der geänderten Dateien abrufen möchten, erweitern wir zuerst alle vom Benutzer bereitgestellten Pfadspezifikationen mit " ls-files" und geben dann die resultierende Liste der Pfade als Argumente an " diff-index" und " diff-files" weiter.
Wenn sich Ihre Pfadspezifikation auf eine große Anzahl von Pfaden erweitert, kann eines von zwei Problemen auftreten:

  1. Das Betriebssystem kann sich über die Größe der Argumentliste beschweren und die Ausführung verweigern. Beispielsweise:

    $ (ulimit -s 128 && git add -p drivers)
    Can't exec "git": Argument list too long at .../git-add--interactive line 177.
    Died at .../git-add--interactive line 177.
    

Das befindet sich im linux.gitRepository, das ungefähr 20.000 Dateien im Verzeichnis "drivers" enthält (keine davon wurde in diesem Fall geändert). Der " ulimit -s" Trick ist notwendig, um das Problem unter Linux auch für solch gigantische Pfade aufzuzeigen.
Andere Betriebssysteme haben viel kleinere Grenzwerte (z. B. wurde unter OS X ein realer Fall mit nur 5K-Dateien festgestellt).

  1. Selbst wenn es funktioniert, ist es sehr langsam. Der Pfadspezifikationscode ist nicht für eine große Anzahl von Pfaden optimiert. Hier ist der gleiche Fall ohne das Ulimit:

    $ time git add -p drivers
      No changes.
    
    real  0m16.559s
    user    0m53.140s
    sys 0m0.220s
    

Wir können dies verbessern, indem wir " ls-files" vollständig überspringen und nur die ursprünglichen Pfadspezifikationen den diff-Befehlen zuführen.

Historisch gesehen war die von " diff-index" unterstützte Pfadspezifikationssprache schwächer, aber das ist nicht mehr der Fall.

VonC
quelle
1

Setzen Sie die Zeile in ~ / .gitconfig

[alias] addt = !sh -c 'git ls-files | grep \"\\.$1*\" | xargs git add' -

Wenn Sie alle geänderten Java-Dateien hinzufügen möchten, können Sie einfach: git addt java

Wenn Sie alle geänderten Python-Dateien hinzufügen möchten, können Sie Folgendes tun: git addt py

Hong Emrys
quelle