Рекурсивно добавлять файлы по шаблону

172

Как рекурсивно добавить файлы по шаблону (или глобусу), расположенным в разных каталогах?

Например, я хотел бы добавить A/B/C/foo.javaи D/E/F/bar.java(и несколько других файлов Java) с помощью одной команды:

git add '*.java'

К сожалению, это не работает, как ожидалось.

Мишель Крамер
источник
2
Это работает для меня (Mac OS X, Git 1.7.1+). Какую версию ОС и Git вы используете?
Крис Джонсен
3
Если у вас есть (уже отслеженные) .javaфайлы в текущем каталоге, вы можете столкнуться со сложной обработкой подстановочных знаков между bash и «помощником» командной строки msys . Я не уверен насчет решения. Вы можете попробовать несколько слоев кавычек: git add '"*.java"'(одинарные кавычки используются bash для предотвращения расширения глобуса, двойные кавычки берутся слоем msys для предотвращения расширения глоба).
Крис Джонсен
1
Спасибо за примечание. К сожалению, это тоже не работает. Они говорят, что это было исправлено, но у меня уже есть последняя версия.
Мишель Крамер
1
git add *.javaработает для меня (на PowerShell с клиентом GitHub)
ThaDafinser

Ответы:

89

Ответ Серхио Акосты, вероятно, является лучшим выбором, если некоторые из файлов, которые будут добавлены, возможно, еще не отслежены. Если вы хотите ограничить себя файлами, о которых git уже знает, вы можете git-ls-filesиспользовать фильтр:

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

Git не предоставляет каких-либо причудливых механизмов для того, чтобы делать это самому, поскольку это в основном проблема оболочки: как получить список файлов, которые будут предоставлены в качестве аргументов для данной команды.

Cascabel
источник
8
Спасибо! Я немного улучшил вашу команду, и теперь она делает то, что искала:git ls-files -co --exclude-standard | grep '\.java$' | xargs git add
Мишель Крамер
169

Вы можете использовать git add [path]/\*.javaдля добавления файлов Java из подкаталогов,
например, git add ./\*.javaдля текущего каталога.

Из git addдокументации :

Добавляет содержимое из всех *.txtфайлов в Documentationкаталоге и его подкаталогах:

$ git add Documentation/\*.txt

Обратите внимание, что звездочка *в этом примере заключена в кавычки из оболочки; это позволяет команде включать файлы из подкаталогов Documentation/каталога.

Сергей Глотов
источник
2
@ MichelKrämer, вероятно, это не так, но сейчас.
Альберто
7
Это лучшее решение, работает и в Windows.
TheTFo
1
"звездочка * указана из оболочки". Я думаю, что вы имеете в виду "сбежал". В любом случае обратная косая черта не позволяет оболочке расширять ее.
gwideman
1
@ всем, я думаю, ты прав, но это не я. Это цитата из документации git-scm.com/docs/git-add#_examples
Сергей Глотов
62

С помощью zshвы можете запустить:

git add "**/*.java"

и все ваши *.javaфайлы будут добавлены рекурсивно.

Оливье Вердиер
источник
Спасибо за это, но я работаю с msysgit в Windows, и он имеет только bash.
Мишель Крамер
1
Ну, я вижу, что есть zshоболочка для окон ... вы сделаете себе одолжение, чтобы использовать ее вместо bash, imho.
Оливье Вердиер
1
Windows-порт zsh основан на очень старой версии и постоянно падает (например, когда я вхожу ls).
Мишель Крамер
Вау, отлично. Я не знал об этой функции!
Томаш Вотруба
1
Это не имеет ничего общего с Zsh. Я думаю, что в этом ответе пропущен момент, когда вы хотите передать путь с неповрежденными подстановочными знаками, чтобы git позволил git обработать его. Таким образом, вы хотите предотвратить использование любой используемой оболочки для подстановочных знаков. Чтобы сделать это, вам нужно указать это так, как это подходит для используемой вами оболочки. Смотрите другие ответы для деталей.
gwideman
55

Немного не по теме (не относящийся конкретно к git), но если вы используете Linux / Unix, обходной путь может быть:

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

И если вы ожидаете пути с пробелами:

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

Но я знаю, что это не совсем то, что вы спросили.

Серхио Акоста
источник
6
Незначительная проблема с этим подходом - если вы «находите» файл, который соответствует вашему .gitignore, то git жалуется, что вы пытаетесь добавить файл, который вы сказали игнорировать.
Йо
2
@yoyo - я просто добавил -f в конце, и это исправило это
Маслоу
5
@Maslow, который принудительно добавит файл, даже если он должен был игнорироваться (на основе .gitignore). Я предпочел бы получить жалобу и не добавлять файл (это поведение по умолчанию)
yoyo
Как это может быть лучше, чем позволить git выполнить расширение по шаблону?
gwideman
12

Ответ Сергея (не верить мне) работает:

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

с недавним мерзавцем:

$git version
git version 1.7.3.4

Файлы для теста:

$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 статус:

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

Добавление * .txt:

$git add \*.txt

Обновленный статус:

$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
источник
8

Если вы уже отслеживаете свои файлы и внесли изменения в них, и теперь вы хотите добавить их выборочно на основе шаблона, вы можете использовать --modifiedфлаг

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

Например, если вы хотите добавить только изменения CSS в этот коммит, вы можете сделать

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

Смотрите man git-ls-filesбольше флагов

ОЗУ
источник
5

Просто используйте git add *\*.java. Это добавит все файлы .java в корневой каталог и все подкаталоги.

Ян Ловстранд
источник
Отличный ответ. Я сделал git add * / pom.xml, чтобы добавить все имена файлов pom.xml.
Филипп Рего
4

Добавление решения для командной строки Windows, которое еще не было упомянуто:

for /f "delims=" %G in ('dir /b/s *.java') do @git add %G
selalerer
источник
3

Я хотел добавить только файлы, которые имели определенную строку на основе git status:

git status | grep string | xargs git add

а затем смог git commit -m 'commit msgзафиксировать все измененные файлы со «строкой» в заголовке файла

bdanin
источник
2

Как упомянуто в « git: Как я могу рекурсивно добавить все файлы в поддереве каталога, которые соответствуют шаблону glob? », Если вы правильно экранируете или цитируете свой globbing pathspec (например,'*.java' ), тогда да, git add'*.java'

Git 2.13 (второй квартал 2017 года) улучшает это для интерактивного добавления

Смотрите коммит 7288e12 (14 марта 2017 г.) Джеффа Кинга ( peff) .
(Слиты Junio C Hamano - gitster- в фиксации 153e0d7 , 17 марта 2017)

add --interactive: не расширяйте pathspecs с помощью ls-files

Когда мы хотим получить список измененных файлов, мы сначала расширяем любые предоставленные пользователем пути с помощью « ls-files», а затем передаем полученный список путей в качестве аргументов « diff-index» и « diff-files».
Если ваша спецификация пути распространяется на большое количество путей, вы можете столкнуться с одной из двух проблем:

  1. ОС может пожаловаться на размер списка аргументов и отказать в запуске. Например:

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

Это находится в linux.gitхранилище, в котором находится около 20 КБ файлов в каталоге «drivers» (в этом случае ни один из них не был изменен). ulimit -sТрюк " " необходим, чтобы показать проблему в Linux даже для такого гигантского набора путей.
Другие операционные системы имеют гораздо меньшие ограничения (например, в реальных случаях было замечено только 5K файлов на OS X).

  1. Даже когда это работает, это действительно медленно. Код pathspec не оптимизирован для огромного количества путей. Вот тот же случай без предела:

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

Мы можем улучшить это, полностью пропустив " ls-files", и просто введя исходные спецификации путей в команды diff.

Исторически язык pathspec, поддерживаемый " diff-index", был слабее, но это уже не так.

VonC
источник
1

поместите строку в ~ / .gitconfig

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

Если вы хотите добавить все измененные файлы Java, просто сделайте: git addt java

Точно так же, если вы хотите добавить все измененные файлы Python, можете просто: git addt py

Хонг Эмрис
источник