Какая разница между Git игнорированием каталога и каталога/*?

Я смущен тем, что правильный способ игнорировать содержимое каталога в git.

Предположим, что у меня есть следующая структура каталогов:

my_project  
     |--www  
         |--1.txt  
         |--2.txt
     |--.gitignore

В чем разница между установкой этого:

www

И это?

www/*

Причина, по которой я задаю этот вопрос: В git, если каталог пуст, git не будет включать такой пустой каталог в репозиторий. Поэтому я пытался найти решение, которое добавляет дополнительный файл .gitkeep в каталог, чтобы он не был пустым. Когда я пытался это решение, если в файле .gitignore я пишу, как показано ниже:

www
!*.gitkeep

Это не работает (я намерен игнорировать все содержимое в разделе www, но сохранить каталог). Но если я попробую следующее:

www/* 
!*.gitkeep

Тогда это сработает! Поэтому я думаю, что это должно иметь некоторые различия между двумя подходами.

Ответ 1

Существуют различия между www, www/ и www/*.

В основном из документации и моих собственных тестов www найти совпадение с файлом или каталогом www/ только соответствует каталогу, а www/* соответствует каталогам и файлам внутри www.

Я расскажу только о различиях между www/ и www/* здесь, так как различия между www и www/ очевидны.

Для www/, git игнорирует сам каталог www, что означает, что git даже не заглянет внутрь. Но для www/*, git проверяет все файлы/папки внутри www и игнорирует их все с помощью шаблона *. Кажется, это приводит к тем же результатам, поскольку git не будет отслеживать пустую папку www, если все ее дочерние файлы/папки игнорируются. И действительно, результаты не будут иметь разницы для случая OP с автономным значением www/ или www/*. Но он делает различия, если он сочетается с другими правилами.

Например, что, если мы хотим включить только www/1.txt, но игнорировать все остальные внутри www?

Следующий .gitignore не будет работать.

www/
!www/1.txt

Пока работает .gitignore, почему?

www/*
!www/1.txt

Для первого, git просто игнорирует каталог www и даже не заглянет внутрь, чтобы включить www/1.txt снова. Первое правило исключает родительский каталог www, но не www/1.txt, и в результате www/1.txt не может быть " включен снова".

Но для последнего git сначала игнорирует все файлы/файлы в www, а затем включает один из них, который является www/1.txt.

В этом примере следующие строки в документации могут помочь:

Дополнительный префикс "!" что отрицает шаблон; любой соответствующий файл исключенный предыдущим шаблоном, снова включается. Это не можно повторно включить файл, если родительский каталог этого файла исключены.

Ответ 2

Я просто разбираюсь в документации, и насколько я могу судить, они отличаются только более продвинутыми шаблонами, например.

$ cat .gitignore
    # exclude everything except directory foo/bar
    /*
    !/foo
    /foo/*
    !/foo/bar

Я проверил выше, и если вы замените !/foo на !/foo/*, вы действительно получите другой результат.

Примечание

foo

Будет исключен любой файл foo, но

foo/

будет исключать только каталоги с именем foo.

Ответ 3

Помимо совершенно хороших ответов, которые вы уже получили, вы должны заметить, что вы можете иметь .gitignore в любом месте вашего проекта, включая подпапки.

Итак, если вы хотите игнорировать все файлы внутри www, но хотите, чтобы папка www была версией, вместо использования пустого .gitkeep, .dummy или любого другого имени, которое вы выберете, почему бы не использовать .gitignore там, говоря игнорировать все файлы?

/
|- .gitignore   (a)
\- www
    |- .gitignore   (b)
    |- 1.jpg
    \- 2.jpg

В корневом каталоге .gitignore (a) вы ничего не скажете о папке www или ее содержимом.

В www/.gitignore (b) вы добавили следующее:

# ignore all files in this folder except this .gitignore
*
!.gitignore

Таким образом, все выглядит более организованным (по крайней мере, для меня).

Ответ 4

Чтобы игнорировать все в каталоге, кроме dotfiles, вы можете использовать следующий шаблон glob в своем .gitignore:

www/[^.]*

Поэтому нет необходимости в дополнительном .gitignore, просто добавьте файл .keep в каталог www.