В чем разница между добавлением bin
, bin/
, bin/*
и bin/**
в мой файл .gitignore? Я использовал bin/
, но смотрел прочее .gitignore файлы (в файле eclipse двойные и одиночные звезды даже используются вместе следующим образом: tmp/**/*
что с этим?) Я вижу, что первые два шаблона также широко используются. Может кто-нибудь объяснить различия между тремя?
.gitignore Синтаксис: bin vs bin/vs. bin/* vs. bin/**
Ответ 1
bin
соответствует любым файлам или каталогам с именем 'bin'.
bin/
соответствует любым каталогам с именем "bin", что фактически означает все его содержимое, поскольку Git не отслеживает только каталоги.
bin/*
соответствует всем файлам и каталогам непосредственно в любом bin/
. Это предотвращает Git автоматически поиск любых файлов в своих подкаталогах, но если, скажем, создается подкаталог bin/foo
, это правило будет не соответствовать foo
содержимому.
bin/**
соответствует всем файлам и каталогам в любом каталоге bin/
и во всех его подкаталогах.
Слово "любое" здесь имеет решающее значение, поскольку правила не относятся к корню репозитория и применяются в любом месте дерева файловой системы. Вы должны начинать правила с /
(или !/
, чтобы игнорировать), что означает корень репозитория, а не системный корень, чтобы соответствовать только тому, что было предназначено.
ПРЕДУПРЕЖДЕНИЕ.. никогда не используйте правила, такие как dir/*
, /dir/**
и т.д., если вы также не игнорируете что-то, что существует внутри этого каталога. Опустите звездочку или вы можете навсегда потерять много данных из определенных вызовов git gc
, git stash
и т.д.
Я действительно не знаю, что делать tmp/**/*
. Первоначально я думал, что он может использоваться для сопоставления файлов в подкаталогах tmp/
, но не файлов, непосредственно присутствующих в tmp/
. Но простой тест, кажется, предполагает, что это игнорирует все файлы в tmp/
.
Ответ 2
bin
и bin/
отличаются только тем, что последний соответствует только каталогу.
bin/**/*
совпадает с bin/**
(по-видимому, с 1.8.2, согласно ответу @VonC).
Трудный, что я просто потратил час или около того, вырывая мои волосы, заключается в том, что bin/
и bin/**
не совсем то же самое! Поскольку ранее игнорирует каталог в целом, а последний игнорирует каждый из файлов внутри него, а git почти во всех случаях не заботится о каталогах, обычно нет разницы. Однако, если вы попытаетесь использовать !
, чтобы игнорировать подпуть, вы обнаружите, что git (ahem) игнорирует его, если вы проигнорировали родительский каталог! (опять же, а не содержимое каталога)
Это яснее на примере, поэтому для недавно созданного репозитория настроено так:
$ cat .gitignore
ignored-file
or-dir
dir-only/
!dir-only/cant-reinclude
dir-contents/**
!dir-contents/can-reinclude
$ mkdir or-dir dir-only dir-contents
$ touch file ignored-file or-dir/ignored-file dir-only/cant-reinclude dir-contents/can-reinclude
Существуют следующие файлы без следа:
$ git ls-files --other
.gitignore
dir-contents/can-reinclude
dir-only/cant-reinclude
file
ignored-file
or-dir/ignored-file
Но вы можете видеть, что следующие файлы не игнорируются:
$ git ls-files --other --exclude-standard
.gitignore
dir-contents/can-reinclude
file
И если вы попытаетесь добавить, вы получите:
$ git add dir-only/cant-reinclude
The following paths are ignored by one of your .gitignore files:
dir-only/cant-reinclude
Use -f if you really want to add them.
fatal: no files added
Я считаю это поведение ошибкой. (Все это на git version 1.8.4.msysgit.0
)
Ответ 3
Обратите внимание, что, строго говоря, git не отслеживает каталоги, только файлы. Поэтому невозможно добавить каталог, только его содержимое.
Однако в контексте .gitignore
git делает вид, что понимает каталоги только по той причине, что
Невозможно повторно включить файл, если родительский каталог этого файла исключен.
https://git-scm.com/docs/gitignore#_pattern_format
Что это значит для шаблонов исключений? Прочтите их подробно:
bin
Это игнорирует
- с именем
bin
. - содержимое папок с именем
bin
Вы можете белыми списками игнорировать bin
файлы и папки, добавляя последующие записи !
, но вы не можете переадресовывать содержимое папок с именем bin
bin
!bin/file_in_bin # has no effect, since bin/ is blacklisted!
!bin/* # has no effect, since bin/ is blacklisted!
!file_in_bin # has no effect, since bin/ is blacklisted!
!bin # this works
bin/
То же, что и выше, за исключением того, что он не соответствует файлам с именем bin
. Добавление конечного /
сообщает git только для сопоставления каталогов.
bin/*
Это игнорирует
- файлы, содержащиеся в папке с именем
bin
- содержимое прямых подпапок папок с именем
bin
bin/* # blacklists bin/file_in_bin and bin/subfolder/
!bin/subfolder/file_in_sub # has no effect, since bin/subfolder is blacklisted!
!bin # whitelists files named bin/bin, since bin/ itself is not blacklisted
!bin/ # has no effect, since bin/ itself is not blacklisted
!bin/file_in_bin # works since bin/ itself is not blacklisted
!file_in_bin # works too
!bin/subfolder # works (so implicitly whitelists bin/subfolder/file_in_sub)
!bin/subfolder/ # works just as well
!bin/* # works for file_in_bin and subfolder/
bin/**
Это игнорирует
- содержимое
bin
- содержимое подпапок (любой уровень вложенности) в
bin
bin/** # blacklists bin/file_in_bin and
# bin/subfolder/ and bin/subfolder/file_in_sub and
# bin/subfolder/2/ and bin/subfolder/2/file_in_sub_2
!bin/subfolder/file_in_sub # has no effect, since bin/subfolder is blacklisted
!bin/subfolder/2/ # has no effect, since bin/subfolder is blacklisted
!bin/subfolder/2/file_in_sub_2 # has no effect, since bin/subfolder is blacklisted
!bin/subfolder # works only in combinations with other whitelist entries,
# since all contents of subfolder are blacklisted (1)
!bin/file_in_bin # works since bin itself is not blacklisted
!bin/* # works for file_in_bin and subfolder; see (1)
Ответ 4
Я только что сделал новое репо и попробовал кое-что. Вот мои результаты:
НОВЫЕ РЕЗУЛЬТАТЫ
git версия 2.10.1.windows.1
- Инициализировать почти пустое репо. Только файл README
- Настройте каталог
bin
на несколько слоев-
bin.txt
-
Test.txt
-
bin/a/b/bin.txt
-
bin/a/b/Test.txt
-
bin/a/bin/bin.txt
-
bin/a/bin/Test.txt
-
bin/a/bin.txt
-
bin/a/Test.txt
-
bin/bin.txt
-
bin/Test.txt
-
- Добавить
bin
в gitignore: Результаты- Все ниже
bin
(и глубже) теперь игнорируется - Уровень корня не игнорируется (/bin.txt и /Test.txt все еще отображаются)
- Все ниже
- Изменить
bin
наbin/
в gitignore: Результаты- Без изменений
- Изменить
bin/
наbin/*
- Без изменений
- Изменить
bin/*
наbin/**
- Без изменений
- Изменить
bin/**
наbin/**/
-
bin/bin.txt
иbin/Test.txt
больше не игнорируются
-
- Изменить
bin/**/
наbin/**/*
-
bin/bin.txt
иbin/Test.txt
возвращаются к игнорированию
-
СТАРЫЕ РЕЗУЛЬТАТЫ
git версия: 2.7.0.windows.1
- Инициализировать почти пустое репо. Только файл README
- Настройте каталог
bin
на несколько слоев-
bin/a/b/Test.txt
-
bin/a/bin/Test.txt
-
bin/a/Test.txt
-
bin/Test.txt
-
- Добавить
bin
в gitignore: Результаты- Все ниже
bin
(и глубже) теперь игнорируется
- Все ниже
- Изменить
bin
наbin/
в gitignore: Результаты- Все под каталогом
bin
(и глубже) по-прежнему игнорируется (без изменений)
- Все под каталогом
- Изменить
bin/
наbin/*
- Все под каталогом
bin
(и глубже) по-прежнему игнорируется (без изменений)
- Все под каталогом
- Изменить
bin/*
наbin/**
- Все под каталогом
bin
(и глубже) по-прежнему игнорируется (без изменений)
- Все под каталогом
- Изменить
bin/**
наbin/**/
-
bin/Test.txt
больше не игнорируется
-
- Изменить
bin/**/
наbin/**/*
- Все под каталогом
bin
(и глубже) снова игнорируется
- Все под каталогом
Ответ 5
Обратите внимание, что '**
', когда он объединен с подкаталогом (**/bar
), должен был измениться по своему поведению, поскольку примечание к выпуску для git1.8.2 теперь упоминает:
Паттерны в файлах
.gitignore
и.gitattributes
могут иметь**/
, как шаблон, который соответствует 0 или более уровням подкаталога.например. "
foo/**/bar
" соответствует "bar
" в "foo
" или в подкаталоге "foo
".
Правило для запоминания (и которое помогает понять разницу намерений за этим синтаксисом):
Невозможно повторно включить файл, если родительский каталог этого файла исключен.
Обычно, если вы хотите исключить файлы из подпапки папки f игнорирования, вы должны:
f/**
!f/**/
!f/a/sub/folder/someFile.txt
То есть:
- Если первое правило было
f/
, папкаf/
была бы проигнорирована, а правила ниже относительноf
не имели бы значения. -
f/**
достичь того же значения, что иf/
, но игнорировать все подэлементы (файлы и подпапки).
Это дает вам возможность вносить в белый список (исключить из gitignore) подпапки:!f/**/
. - Поскольку все подтексты
f
не игнорируются, вы можете добавить правило для исключения файла (!f/a/sub/folder/someFile.txt
)
Ответ 6
Существует еще одно отличие между bin/*
и bin/
.
bin/
соответствует foo/bin/test.txt
(как и ожидалось), но bin/*
нет, что кажется странным, но оно документировано: https://git-scm.com/docs/gitignore
"Документация/*. html" соответствует "Документация/ git.html", но не "Документация/ppc/ppc.html" или "tools/perf/Documentation/perf.html".
Причиной этого являются следующие правила:
Если шаблон заканчивается косой чертой, он удаляется с целью следующего описания & hellip;
Если шаблон не содержит косой черты /, Git рассматривает его как шаблон оболочки оболочки и проверяет соответствие имени пути относительно местоположения файла .gitignore & hellip;
В противном случае Git рассматривает шаблон как оболочку оболочки, подходящую для использования fnmatch (3) с флагом FNM_PATHNAME & hellip;
Итак, если шаблон заканчивается косой чертой, косая черта удаляется и обрабатывается как шаблон оболочки оболочки, и в этом случае bin
соответствует foo/bin/test.txt
.
Если он заканчивается на /*
, косая черта не удаляется и передается fnmatch, что не соответствует в подкаталогах.
Однако это не так для foo/bin/
и foo/bin/*
, потому что даже после удаления конечной косой черты из foo/bin/
он все еще содержит косую черту, поэтому он рассматривается как шаблон fnmatch, а не glob. То есть он не будет соответствовать bar/foo/bin/test.txt