Разница в путях в файле .gitignore? - PullRequest
56 голосов
/ 25 марта 2009

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

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

tmp/*
public/documents/**/*

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

Ответы [ 6 ]

55 голосов
/ 25 марта 2009

Это зависит от поведения вашей оболочки. 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
15 голосов
/ 31 декабря 2010

Обновление (08-Mar-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 и файлами на нескольких уровнях подкаталогов.

Для OP я перепробовал каждую комбинацию для файла .gitignore, и ничто не работает лучше, чем это:

public/documents/

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

public/documents/**/*.obj

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

15 голосов
/ 25 марта 2009

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

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

/tmp/*.log

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

/tmp/**/*.log

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

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

tmp/*

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

/tmp

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

14 голосов
/ 18 февраля 2013

Обратите внимание, что '**', в сочетании с подкаталогом (**/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" ..

Подписано: Nguy Thn Thái Ngọc Duy <pclouds@gmail.com>


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

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

Справочная страница .gitignore упоминает:

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

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

5 голосов
/ 02 июня 2011

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

public/documents/**/*

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

public/documents/*/*
2 голосов
/ 27 мая 2009

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

tmp/**/*.log

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

*.log
...