Git определяет рекурсивное поведение для шаблонов gitignore? - PullRequest
0 голосов
/ 12 января 2019

Это точный вопрос как Где указано рекурсивное поведение gitignore? , потому что я не думаю, что его принятый ответ объясняет, что в документации git определяет рекурсивное поведение паттернов gitignore.

Рассмотрим следующий сценарий. Структура хранилища:

.gitignore
a
|
-- f

(то есть в корне хранилища находится файл .gitignore и папка с именем a, а внутри a есть файл с именем f)

Файл .gitignore в корне хранилища содержит f в качестве единственного шаблона.

Теперь, если бы мы прочитали документацию gitignore , мы бы нашли следующий параграф (выделено мной):

Если шаблон не содержит косую черту /, Git обрабатывает его как шаблон оболочки и проверяет совпадение с путевым именем относительно расположения файла .gitignore (относительно верхнего уровня рабочее дерево, если не из файла .gitignore).

Из приведенного выше абзаца я понимаю, что когда git проверяет, должен ли файл f быть проигнорирован или нет, он будет пытаться сопоставить его " pathname относительно местоположения файла .gitignore «к шаблону. Поэтому он попытается сопоставить шаблон f с a/f, который не должен совпадать.

Неужели мое понимание неверно? Спасибо.

1 Ответ

0 голосов
/ 12 января 2019

Вы неправильно читаете жирную фразу (что, я признаю, легко сделать - документация Git часто оставляет желать лучшего).

Что означает фраза "относительно местоположения файла .gitignore" , пытаясь передать эту идею:

.gitignore
bar
dir/
    dir/.gitignore
    dir/bar
    dir/hello
foo
hello

Предположим, что .gitignore состоит из строки hello, а dir/.gitignore состоит из строки bar. Файл hello в в обоих каталогах игнорируется, поскольку hello игнорируется на верхнем уровне, а файл bar в верхнем каталоге не игнорируется, поскольку bar игнорируется dir/.gitignore, что влияет только на файлы в dir и подкаталогах dir.

Asides

  1. Материал, касающийся косых черт в шаблонах в записях .gitignore, особенно сложен. В документации говорится, что (один) конечный слеш временно удаляется для принятия решения: содержит ли этот элемент слеш? Затем он возвращается. Я думаю, что лучший способ сформулировать это - не то, что Git делает так, - это сказать: «Запись укоренена тогда и только тогда, когда она содержит косую черту, которая не является последним символом в записи». Эта идея «укоренения» означает, что полное (относительное к .gitignore -location) имя пути должно совпадать. В противном случае шаблон будет совпадать как в этом каталоге, так и во всех его подкаталогах, что является более или менее той же проблемой, с которой вы здесь сталкиваетесь.

  2. Помните, что .gitignore на самом деле не означает игнорировать . В основном это означает, что не жалуйтесь на неотслеживаемые файлы.

    Файлы отслеживаются , если и только если они находятся в Git's index . Содержимое индекса со временем меняется - изначально оно «независимо от того, что было в коммите, который вы только что извлекли», но вы можете заменить находящиеся в нем файлы или поместить в него новые git add, и вы можете удалите файлы из него с помощью git rm (или, в этом отношении, с git add!). Если файл отслеживается , т. Е. Если имя этого файла находится в индексе прямо сейчас , то любое совпадение имени этого файла с любой записью .gitignore не имеет значения.

  3. Отслеживаются только файлы . Из-за этого факта, запись .gitignore для каталога, ну, странно. Каталог никогда не будет отслеживаться. Эффект имени каталога в .gitignore, соответственно, особенно странный и хитрый.

    Внутренняя, ориентированная на производительность цель - игнорировать весь каталог в Git не столько для того, чтобы упростить процесс выражения пользователем, сколько для того, чтобы заставить Git работать очень быстро, как гоночный автомобиль, который вы можете использовать. проехать 700 миль в час по обрыву! "

    Одна из более медленных частей Git - перечисление, по одному файлу за раз, каждому файлу и подкаталогу, а также файлам всех подкаталогов в некотором каталоге, потому что Git должен постоянно спрашивать ОС, по одному файлу за раз, около каждого из этих файлов (сделать lstat системных вызовов). Люди из Git заметили, что если бы вы могли как-то сказать Git: даже не заглянуть внутрь каталог vendor , вы могли бы пропустить тысячи файлов SDK, которые вы вставили в там, делая git status так намного быстрее.

    С этой целью, если вы укажете vendor или vendor/ (или /vendor/ для корня шаблона в каталоге, содержащем файл .gitignore), и Индекс Git имеет в нем нет файлов с именем vendor/<em>anything</em>, , затем - и только тогда - Git может пропустить прямо по каталогу vendor и не потрудиться перечислять тысячи файлов SDK.

    На другомС другой стороны, если вы перечислите vendor/* или /vendor/* - оба из них означают одно и то же, поскольку оба содержат /, который не является окончательным / - Git придется открывать и читать каталог vendor. Независимо от того, находятся ли все десять тысяч файлов (и / или подкаталогов) на верхнем уровне этого каталога, Git сможет их пропустить - в конце концов, они соответствуют vendor/* - но сначала ему нужно будет перечислить по крайней мере, верхний уровень каталога vendor. Этот процесс перечисления дает вам возможность затем un - игнорировать любой конкретный подкаталог или файл, такой как vendor/REMEMBER_WHICH_VERSION_WE_GOT (хотя, вероятно, лучше помнить, что за пределами субподрядчика поставщика дерево).

    (Обратите внимание, что, если в каком-то каталоге есть отслеживаемый файл, Git обязан заглянуть внутрь этого каталога, даже если каталог номинально игнорируется. Так что этот make-the-race-car-go-fast-even-if- Трюк "есть скала рядом" применяется только тогда, когда там нет отслеживаемых файлов, то есть, принудительное отслеживание файла в Git также гарантирует, что в этой довольно запутанной аналогии также нет обрыва.)

...