Rekurencyjnie dodawaj pliki według wzorca

172

Jak rekurencyjnie dodawać pliki według wzorca (lub globu) znajdującego się w różnych katalogach?

Na przykład chciałbym dodać A/B/C/foo.javai D/E/F/bar.java(i kilka innych plików java) za pomocą jednego polecenia:

git add '*.java'

Niestety to nie działa zgodnie z oczekiwaniami.

Michel Krämer
źródło
2
U mnie działa (Mac OS X, Git 1.7.1+). Jakiej wersji systemu operacyjnego i Git używasz?
Chris Johnsen
3
Jeśli masz jakieś (już śledzone) .javapliki w swoim bieżącym katalogu, być może masz do czynienia ze skomplikowaną obsługą symboli wieloznacznych między bash a „pomocnikiem” wiersza poleceń msys . Nie jestem pewien rozwiązania. Możesz wypróbować wiele warstw cudzysłowów: git add '"*.java"'(pojedyncze cudzysłowy są pobierane przez bash, aby zapobiec rozszerzaniu globów, podwójne cudzysłowy są pobierane przez warstwę msys, aby zapobiec rozszerzaniu globów).
Chris Johnsen
1
Dzięki za wiadomość. Niestety to też nie działa. Mówią, że został naprawiony, ale mam już najnowszą wersję.
Michel Krämer
1
git add *.javadziała dla mnie (na PowerShell z klientem GitHub)
ThaDafinser

Odpowiedzi:

89

Odpowiedź Sergio Acosty jest prawdopodobnie najlepszym rozwiązaniem, jeśli niektóre z plików do dodania mogą nie być jeszcze śledzone. Jeśli chcesz ograniczyć się do plików, o których git już wie, możesz połączyć git-ls-filesz filtrem:

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

Git nie dostarcza żadnych wymyślnych mechanizmów, aby zrobić to sam, ponieważ jest to w zasadzie problem powłoki: jak uzyskać listę plików, które mają być dostarczone jako argumenty dla danego polecenia.

Cascabel
źródło
8
Dzięki! Poprawiłem nieco twoje polecenie i teraz robi to, czego szukałem:git ls-files -co --exclude-standard | grep '\.java$' | xargs git add
Michel Krämer
169

Możesz użyć, git add [path]/\*.javaaby dodać pliki java z podkatalogów,
np. git add ./\*.javaDla bieżącego katalogu.

Z git adddokumentacji :

Dodaje zawartość ze wszystkich *.txtplików w Documentationkatalogu i jego podkatalogach:

$ git add Documentation/\*.txt

Zauważ, że gwiazdka *jest cytowana z powłoki w tym przykładzie; dzięki temu polecenie będzie zawierało pliki z podkatalogów Documentation/katalogu.

Siergiej Głotow
źródło
2
@ MichelKrämer prawdopodobnie nie było, ale jest teraz.
Alberto,
7
To najlepsze rozwiązanie, sprawdza się również w oknach.
TheTFo
1
„gwiazdka * jest cytowana z powłoki”. Myślę, że masz na myśli „uciekł”. W każdym razie odwrotny ukośnik zapobiega rozszerzaniu go przez powłokę.
gwideman
1
@gwideman Myślę, że masz rację, ale to nie ja. To cytat z dokumentacji git-scm.com/docs/git-add#_examples
Sergey Glotov
62

Dzięki zshniemu możesz biegać:

git add "**/*.java"

a wszystkie twoje *.javapliki zostaną dodane rekurencyjnie.

Olivier Verdier
źródło
Dzięki za to, ale pracuję z msysgit na Windows i ma tylko bash.
Michel Krämer
1
Cóż, widzę, że jest zshpowłoka na okna ... zrobisz sobie przysługę, używając jej zamiast bash, imho.
Olivier Verdier
1
Port zsh w systemie Windows jest oparty na bardzo starej wersji i cały czas ulega awarii (na przykład, gdy wchodzę ls).
Michel Krämer
Wow, doskonale. Nie wiedziałem o tej funkcji!
Tomáš Votruba
1
To nie ma nic wspólnego z zsh. Myślę, że ta odpowiedź pomija punkt, w którym chcesz przejść ścieżkę z nienaruszonymi symbolami wieloznacznymi, aby git i pozwolić gitowi to przetworzyć. Dlatego chcesz, aby powłoka, której używasz, nie rozwijała symboli wieloznacznych. Aby to zrobić, musisz zacytować to w sposób odpowiedni dla używanej powłoki. Zobacz inne odpowiedzi, aby uzyskać szczegółowe informacje.
gwideman
55

Trochę poza tematem (nie dotyczy konkretnie git), ale jeśli korzystasz z Linuksa / Uniksa, obejściem może być:

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

A jeśli spodziewasz się ścieżek ze spacjami:

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

Ale wiem, że to nie jest dokładnie to, o co prosiłeś.

Sergio Acosta
źródło
6
Drobny problem z tym podejściem - jeśli "znajdziesz" plik, który pasuje do twojego .gitignore, wtedy git narzeka, że ​​próbujesz dodać plik, który kazałeś mu zignorować.
jojo
2
@yoyo - właśnie dodałem -f na końcu i to naprawiło
Maslow
5
@Maslow, który wymusi dodanie pliku, mimo że miał zostać zignorowany (na podstawie .gitignore). Wolałbym otrzymać skargę i nie dodawać pliku (co jest zachowaniem domyślnym).
yoyo
W jaki sposób jest to lepsze niż pozwolenie gitowi na rozwinięcie symboli wieloznacznych?
gwideman
12

Odpowiedź Siergieja (nie wierz mi) działa:

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

z niedawnym gitem:

$git version
git version 1.7.3.4

Pliki do testu:

$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

Stan Git:

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

Dodawanie * .txt:

$git add \*.txt

Zaktualizowany stan:

$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
źródło
8

Jeśli już śledzisz swoje pliki i dokonałeś w nich zmian, a teraz chcesz je dodać selektywnie na podstawie wzorca, możesz użyć --modifiedflagi

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

Na przykład, jeśli chcesz tylko dodać zmiany CSS do tego zatwierdzenia, możesz to zrobić

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

Zobacz man git-ls-fileswięcej flag

Baran
źródło
5

Po prostu użyj git add *\*.java. Spowoduje to dodanie wszystkich plików .java do katalogu głównego i wszystkich podkatalogów.

Jan Lovstrand
źródło
Świetna odpowiedź. Zrobiłem git add * / pom.xml, aby dodać wszystkie nazwy plików pom.xml.
Philip Rego
4

Dodanie rozwiązania wiersza poleceń systemu Windows, o którym jeszcze nie wspomniano:

for /f "delims=" %G in ('dir /b/s *.java') do @git add %G
selalerer
źródło
3

Chciałem tylko dodać pliki, które miały określony ciąg oparty na git status:

git status | grep string | xargs git add

a następnie był w stanie git commit -m 'commit msgzatwierdzić wszystkie zmienione pliki ze słowem „string” w tytule pliku

bdanin
źródło
2

Jak wspomniano w " git: Jak rekurencyjnie dodać wszystkie pliki w poddrzewie katalogu, które pasują do wzorca glob? ", Jeśli poprawnie zmienisz ścieżkę lub zacytujesz swoją ścieżkę globbing (jak '*.java'), to tak, git dodaj'*.java'

Git 2.13 (Q2 2017) ulepsza to dla interaktywnego dodatku:

Zobacz commit 7288e12 (14 marca 2017) autorstwa Jeffa Kinga ( peff) .
(Scalone przez Junio ​​C Hamano - gitster- w zobowiązaniu 153e0d7 , 17 marca 2017 r.)

add --interactive: nie rozwijaj pathspecs z ls-files

Kiedy chcemy uzyskać listę zmodyfikowanych plików, najpierw rozszerzamy wszystkie podane przez użytkownika ścieżki o " ls-files", a następnie podajemy wynikową listę ścieżek jako argumenty do " diff-index" i " diff-files".
Jeśli twoja ścieżka rozszerza się na dużą liczbę ścieżek, możesz napotkać jeden z dwóch problemów:

  1. System operacyjny może narzekać na rozmiar listy argumentów i odmówić uruchomienia. Na przykład:

    $ (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.
    

To jest w linux.gitrepozytorium, które ma około 20K plików w katalogu "drivers" (żaden z nich nie został zmodyfikowany w tym przypadku). ulimit -sSztuczka " " jest konieczna, aby pokazać problem w Linuksie, nawet dla tak gigantycznego zestawu ścieżek.
Inne systemy operacyjne mają znacznie mniejsze ograniczenia (np. Rzeczywista sytuacja była widziana tylko z plikami 5K na OS X).

  1. Nawet jeśli działa, jest naprawdę powolny. Kod pathspec nie jest zoptymalizowany pod kątem dużej liczby ścieżek. Oto ten sam przypadek bez ulimitu:

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

Możemy to poprawić ls-filescałkowicie " " pomijając i przekazując oryginalne pathspec do poleceń diff.

Historycznie, język pathspec obsługiwany przez „ diff-index” był słabszy, ale już tak nie jest.

VonC
źródło
1

umieść linię w ~ / .gitconfig

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

Jeśli chcesz dodać wszystkie zmodyfikowane pliki java, możesz po prostu zrobić: git addt java

Samely, jeśli chcesz dodać cały zmodyfikowany plik Pythona, możesz po prostu zrobić: git addt py

Hong Emrys
źródło