Когда использовать свинцовую косую черту в gitignore

Я пытаюсь лучше понять синтаксис .gitignore, и в частности, что касается https://github.com/github/gitignore gitignores.

Я вижу, что ведущая косая черта используется для сопоставления только путей по отношению к расположению файла .gitignore (от http://git-scm.com/docs/gitignore):

Ведущая косая черта соответствует началу пути. Например, "/*.c" соответствует "cat-file.c", но не "mozilla-sha1/sha1.c".

Но что происходит, когда я удаляю ведущую косую черту? Насколько я понял, есть два случая:

  • Если шаблон не содержит косой черты (или содержит только конечную косую черту, что означает, что она должна соответствовать каталогу), поиск выполняется внутри всего дерева каталогов. Например, шаблон dir/ будет соответствовать <root>/dir, <root>/a/dir, <root>/a/b/c/.../dir и т.д., Где <root> - это местоположение файла .gitignore.
  • Если шаблон содержит косую черту, которая не находится в конечной позиции (это не последний символ), тогда она сопоставляется только с именами путей относительно расположения файла .gitignore.

Вот примеры, которые я сделал для проверки этого поведения:

# Directory structure:
<root>
|- dir/
|   |- test
|- src/
|   |- dir/
|   |   |- test
test file is there only because Git does not track empty directories.

Первый тест:

# .gitignore
dir/

# git status
nothing to commit

Итак, Git игнорирует оба каталога dir. Это соответствует случаю номер 1: шаблон не имеет косых черт (кроме конечного), поэтому Git просматривает все дерево каталогов, игнорируя все, что соответствует шаблону.

Второй тест:

# .gitignore
/dir/

# git status
Untracked files:
    src/

Здесь Git игнорирует только каталог dir непосредственно под корневым каталогом, благодаря ведущей косой чертой в шаблоне.

Третий тест:

# .gitignore
dir/*

# git status
Untracked files:
    src/

Это согласуется с номером дела 2: шаблон имеет некоторую косую черту внутри него, поэтому он рассматривается как путь, начинающийся с корневого каталога.

Теперь настало время для настоящего вопроса. Давайте рассмотрим этот файл gitignore: например, если они игнорируют каталог downloader/, они не игнорируют каждый отдельный каталог downloader, найденный во всем дереве каталогов? Это то, что я задумал, так как раньше я видел около Git.

Итак, если у меня есть пользовательский модуль с каталогом downloader внутри него, будет ли он неожиданно проигнорирован, а также обычный в корне Magento? Это немного ретрительный вопрос, потому что это на самом деле со мной произошло, создавая очень трудную ошибку.

Итак, в файле Magento .gitignore (который я имею в виду только в качестве примера, btw) многие шаблоны содержат косые черты, поэтому они правильно сопоставлены с именами пути, начиная с корня, но есть несколько случаев, например downloader/ или errors/, которые, если я не ошибаюсь, потенциально опасны и, вероятно, должны быть изменены на /downloader/ и /errors/.

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

Спасибо за чтение и извините за длинный пост.

Ответ 1

Вы полностью ответили на свой вопрос. Если вы посмотрите более внимательно на github/gitignore repo, вы увидите, что большинство файлов используют противоречивые правила о том, как написаны шаблоны; очень вероятно, что большинство из них были внесены людьми, которые не удосужились прочитать документацию и не проверить, как вы это делали.

Итак, если это помогает: вы правы, будьте уверены.

Если вы видите ошибки в таких совлокальных проектах, не стесняйтесь вкладывать свои знания. Там даже некоторый прецедент, если вам нужно еще больше повысить свою уверенность.

Ответ 2

Просто хотел подвести итоги для возможной быстрой справки в будущем - ведущая косая черта соответствует совпадению с корнем. Таким образом, в приведенном ниже примере без косой черты подстановочный знак также исключает все внутри foo, потому что он принимает * и рекурсивно перемещается по дереву. Однако с /* он исключает все, кроме папки foo и ее содержимого:

$ cat .gitignore
/*
!/foo