Разница в путях в файле .gitignore?

Я использую git, но все еще не могу понять пути к файлам .gitignore.

Итак, в чем разница между следующими двумя путями в файле .gitignore?

tmp/*
public/documents/**/*

Я понимаю, что tmp/* будет игнорировать все файлы и папки внутри него. Я прав? Но что означает этот второй путь?


person Autodidact    schedule 25.03.2009    source источник
comment
Пожалуйста, измените принятый ответ. Это неправильно, и этот миф гуляет по сети.   -  person cdunn2001    schedule 26.07.2011
comment
Просто в дополнение: кажется, что fnmatch в MacOS отличается от Linux. Надеюсь, кто-то еще это проверит.   -  person cdunn2001    schedule 30.07.2011
comment
Эта ветка (thread.gmane.org/gmane.comp.version-control .git/188174) и отсутствие возражений против патча говорит о том, что разработчики не думают, что это где-то работает.. Double asterisk does not have a special meaning and is interpreted just like a single asterisk.   -  person antak    schedule 13.08.2012
comment
Начиная с git1.8.2 (начало 2013 г.), '**' работает лучше, не в зависимости от оболочки. См. мой ответ ниже.   -  person VonC    schedule 17.07.2013
comment
@cdunn2001, (текущий принятый ответ)[stackoverflow.com/a/681294/1995714] принадлежит Джону Феминелле ( ред. 2). Это все тот же неправильный?   -  person cp.engr    schedule 04.03.2016
comment
@cp.engr, сегодня я не могу найти машину, на которой ** не работает, как заявлено. Сюда входят OSX-10.11.3 (El Capitan) и Ubuntu-14.04.1 (Trusty). Возможно, git-ignore как обновленный, или, возможно, недавний fnmatch обрабатывает **, как ожидают люди. Таким образом, принятый ответ теперь может быть правильным на практике.   -  person cdunn2001    schedule 08.03.2016


Ответы (6)


Это зависит от поведения вашей оболочки. Git не делает никакой работы, чтобы определить, как их расширять. Как правило, * соответствует любому отдельному файлу или папке:

/a/*/z
 matches        /a/b/z
 matches        /a/c/z
 doesn't match  /a/b/c/z

** соответствует любой строке папок:

/a/**/z
 matches        /a/b/z
 matches        /a/b/c/z
 matches        /a/b/c/d/e/f/g/h/i/z
 doesn't match  /a/b/c/z/d.pr0n

Объедините ** с *, чтобы найти файлы во всем дереве папок:

/a/**/z/*.pr0n
 matches        /a/b/c/z/d.pr0n
 matches        /a/b/z/foo.pr0n
 doesn't match  /a/b/z/bar.txt
person John Feminella    schedule 25.03.2009
comment
Нет. Это зависит от fnmatch, а не от оболочки. bash-4 поддерживает это, но git игнорирует ** на моей машине, где работает bash-4. Я не знаю нигде, что ** означает что-нибудь. Большинство людей, комментирующих это, на самом деле не проверяли это. Если вы тестировали это с помощью git (а не оболочки), опубликуйте свой O/S. Попробуйте git -nv для тестирования. - person cdunn2001; 26.07.2011
comment
@cdunn2001: я только что перепроверил; это работает, как и ожидалось для меня. Я использую ночную сборку Ubuntu с bash version 4.2.8(1)-release (x86_64-pc-linux-gnu). Если вы непреклонны в том, что это неверно, я буду рад продолжить расследование. - person John Feminella; 26.07.2011
comment
Вы тестируете bash или git? Я не сомневаюсь, что bash работает так, как рекламируется, по крайней мере, с соответствующими настройками. git -nv add . - это способ проверить это. Попробовав именно эти тесты, я почти уверен, что git не работает таким образом на MacOS. Возможно, есть разница между fnmatch в Linux и MacOS. (git использует fnmatch, а не оболочку для этого совпадения.) Не могли бы вы выполнить свои тесты на MacOS, чтобы перепроверить мои собственные? - person cdunn2001; 30.07.2011
comment
Я использую git -nv add .. У меня нет OSX для тестирования, но я спрошу члена команды. - person John Feminella; 30.07.2011
comment
git определенно использует fnmatch, проверьте dir.c в источнике git. @ cdunn2001 на 100% прав, что поддержка ** в стиле ANT зависит от fnmatch. Большинство реализаций fnamtch (например, BSD, GNU libiberty) сворачивают несколько звезд, как если бы они были одной, не зная, какие реализации соответствуют ** в стиле ANT. - person vladr; 29.10.2012
comment
У меня работает, хотя сейчас 2020 год. - person not2qubit; 14.11.2020

Обновление (08 марта 2016 г.)

Сегодня я не могу найти машину, на которой ** не работает так, как заявлено. Сюда входят OSX-10.11.3 (El Capitan) и Ubuntu-14.04.1 (Trusty). Возможно, git-ignore как обновленный, или, возможно, недавний fnmatch обрабатывает **, как ожидают люди. Таким образом, принятый ответ теперь кажется правильным на практике.


Исходный пост

** не имеет особого значения в git. Это функция bash >= 4.0, через

shopt -s globstar

Но git не использует bash. Чтобы увидеть, что на самом деле делает git, вы можете поэкспериментировать с git add -nv и файлами в нескольких уровнях подкаталогов.

Что касается ОП, я перепробовал все возможные комбинации для файла .gitignore, и ничего не работает лучше, чем это:

public/documents/

Следующее не делает то, что все, кажется, думают:

public/documents/**/*.obj

Я не могу заставить это работать, что бы я ни пытался, но, по крайней мере, это согласуется с git< /em> документы. Я подозреваю, что когда люди добавляют это в .gitignore, это работает случайно, только потому, что их файлы .obj имеют глубину ровно в один подкаталог. Вероятно, они скопировали двойную звездочку из bash-скрипта. Но, возможно, есть системы, в которых fnmatch(3) может обрабатывать двойную звездочку так же, как bash.

person cdunn2001    schedule 31.12.2010

Если вы используете такую ​​оболочку, как Bash 4, то ** по сути является рекурсивной версией *, которая будет соответствовать любому количеству подкаталогов.

Это имеет больше смысла, если вы добавите расширение файла к своим примерам. Чтобы сопоставить файлы журналов непосредственно внутри tmp, введите:

/tmp/*.log

Чтобы сопоставить файлы журналов в любом подкаталоге tmp, введите:

/tmp/**/*.log

Но при тестировании с git версии 1.6.0.4 и bash версии 3.2.17(1) оказалось, что git вообще не поддерживает ** globs. В последней справочной странице для gitignore также не упоминается **, так что это либо ( 1) очень новое, (2) неподдерживаемое или (3) каким-то образом зависящее от реализации подстановки в вашей системе.

Кроме того, в ваших примерах происходит что-то тонкое. Это выражение:

tmp/*

... на самом деле означает «игнорировать любой файл внутри каталога tmp, в любом месте исходного дерева, но не игнорировать сами каталоги tmp». В обычных обстоятельствах вы, вероятно, просто написали бы:

/tmp

... который будет игнорировать один каталог tmp верхнего уровня. Если вам нужно сохранить каталоги tmp, игнорируя их содержимое, вы должны поместить пустой файл .gitignore в каждый каталог tmp, чтобы убедиться, что git действительно создает каталог.

person emk    schedule 25.03.2009
comment
Ответ (3): на странице руководства ясно сказано, что глобус будет передан без изменений в системную библиотечную функцию fnmatch. Поэтому поведение gitignore globs зависит от системы. - person Jörg W Mittag; 25.03.2009
comment
Вы правы - справочная страница предполагает, что случай (3) является правильным ответом. Но я столкнулся с несколькими случаями, когда справочные страницы git немного устарели, поэтому я не собираюсь давать конкретный ответ, не прочитав код. - person emk; 25.03.2009
comment
Кстати, tmp/* будет соответствовать только на верхнем уровне. Правило состоит в том, что любой символ «/», кроме одного в конце, переключает вас в режим точного совпадения. Начальная косая черта нужна только в том случае, если нет других. - person Ben Martin; 18.06.2012

Обратите внимание, что '**', в сочетании с подкаталогом (**/bar), должен был отличаться от своего поведения по умолчанию, так как примечание к выпуску git1.8.2 теперь упоминает:

Шаблоны в файлах .gitignore и .gitattributes могут иметь **/ в качестве шаблона, который соответствует 0 или более уровням подкаталога.

Например. "foo/**/bar" соответствует "bar" в самом "foo" или в подкаталоге "foo".


См. commit 4c251e5cb5c245ee3bb98c7cedbe944df93e45f4:

"foo/**/bar" соответствует "foo/x/bar", "foo/x/y/bar"... но не "foo/bar".
Мы делаем особый случай, когда обнаруживается foo/**/ (и часть "foo/" уже совпала), попробуйте сопоставить "bar" с остальная часть строки.

Семантика «Соответствие одному или нескольким каталогам» может быть легко достигнута с помощью «foo/*/**/bar».

Это также делает "**/foo" совпадающим с "foo" в дополнение к "x/foo", "x/y/foo".

Подписал: Нгуен Тай Нгок Дуй <[email protected]>


Саймон Бьюкен также прокомментировал:

текущие документы (.gitignore справочная страница) довольно ясно показывают, что подкаталог не нужен, x/** соответствует всем файлам под (возможно пустым) x

На справочной странице .gitignore действительно упоминается:

Завершающий "/**" соответствует всему внутри. Например, «abc/**» соответствует всем файлам внутри каталога «abc» относительно местоположения файла .gitignore с бесконечной глубиной.

Косая черта, за которой следуют две последовательные звездочки, после чего косая черта соответствует нулю или более каталогам. Например, «a/**/b» соответствует «a/b», «a/x/b», «a/x/y/b» и так далее.

person VonC    schedule 18.02.2013
comment
+1 за самый точный текущий ответ, но текущие документы довольно ясно показывают, что подкаталог не нужен, x/** соответствует всем файлам в (возможно, пустым) x - обратите внимание, что это может быть изменение по сравнению с 1.8.2 - person Simon Buchan; 05.12.2013
comment
@SimonBuchan Интересно. Я включил ваш комментарий в ответ для большей наглядности. Обратите внимание, что он уже был частью версии 1.8.2 (март 2012 г.), так как с тех пор по этой теме был сделан только один коммит: github.com/git/git/commits/master/wildmatch.c - person VonC; 05.12.2013
comment
Примечание для себя: см. также stackoverflow.com/a/20391855/6309 разницу между игнорированием x/ и x/**. - person VonC; 05.12.2013

Когда ** не поддерживается, «/» по сути является завершающим символом для подстановочного знака, поэтому, когда у вас есть что-то вроде:

public/documents/**/*

по сути, он ищет два элемента подстановки между косыми чертами и не подбирает косые черты сами по себе. Следовательно, это будет то же самое, что и:

public/documents/*/*
person Hazok    schedule 02.06.2011

У меня это не работает, но вы можете создать новый .gitignore в этом подкаталоге:

tmp/**/*.log

можно заменить на .gitignore в tmp:

*.log
person Community    schedule 27.05.2009