gitignore: игнорировать все файлы в иерархии папок, кроме одного определенного типа файла - PullRequest
25 голосов
/ 18 октября 2011

Я хотел бы игнорировать все файлы ниже и в папке, кроме определенного типа файла, который может быть где-то в иерархии папок:

Пример

/Test
/Test/unknown/folder/structure/below

Теперь я хотел быигнорировать все файлы в папке Test и ниже, кроме определенного файла CSS с именем layout.css, например:

/Test/layout.css
/Test/fileto.ignore
/Test/another/folder/ig.nore
/Test/in/a/unknown/folder/layout.css
/Test/in/a/unknown/folder/ignore.me

.gitignore должен игнорировать

/Test/fileto.ignore
/Test/another/folder/ig.nore
/Test/in/a/unknown/folder/ignore.me

Мой файл .gitignoreне работает:

Test/
!layout.css

Есть предложения?

Ответы [ 3 ]

27 голосов
/ 18 октября 2011

Я смог заставить ваш пример работать, поместив файл .gitignore в каталог Test/ со следующим содержимым.

*
!*/
!.gitignore
!layout.css
11 голосов
/ 13 февраля 2015

Чтобы выполнить то, что вы хотите, вам нужно использовать некоторые отрицательные исключения.

Основная идея заключается в том, что вам нужно исключить каждый родительский каталог из любого файла, который вы хотите игнорировать.

Итак, если вы хотите, чтобы /Test/in/a/unknown/folder/layout.css был добавлен в ваше git-репо, вам придется проигнорировать / Test /, / Test / in /, / Test / в / a /, / Test / in / a / unknown / и /Test/in/a/unknown/folder/.

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

# Fille: .gitignore
!Test/
Test/*
!Test/layout.css
Test/fileto.ignore
!Test/another/
Test/another/*
!Test/another/folder/
Test/another/folder/*
!Test/in/
Test/in/*
!Test/in/a/
Test/in/a/*
!Test/in/a/unknown/
Test/in/a/unknown/*
!Test/in/a/unknown/folder/
Test/in/a/unknown/folder/ignore.me
!Test/in/a/unknown/folder/layout.css

Поэтому, когда вы запустите $ git add-all, вы увидите желаемые результаты:

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   .gitignore
    new file:   Test/in/a/unknown/folder/layout.css
    new file:   Test/layout.css

Примечание. Вы можете найти объяснение того, почему git add-all - лучший способ добавить файлы в репозиторий git на http://lexsheehan.blogspot.com/2014/05/git-add-update.html

.
9 голосов
/ 13 декабря 2016

Довольно старый вопрос, но так как я боролся с этой проблемой, даже сейчас, я решил, что поделюсь фактическим решением проблемы.

Дело в том, что пока вы не можете зафиксировать пустые каталоги в Git, как если бы они были проигнорированы, это правило не применяется к .gitignore.

С https://git -scm.com / docs / gitignore

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

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

** Соответствует всему внутри - буквально всему - файлам И каталогам.

Это приводит нас к следующему пункту в gitignore docs:

Необязательный префикс "!" который отрицает образец; любой соответствующий файл исключен по предыдущему шаблону, снова будет включен. Это не можно повторно включить файл, если родительский каталог этого файла исключены. Git не выводит список исключенных каталогов для производительности причины, поэтому любые шаблоны на содержащиеся файлы не имеют никакого эффекта, независимо от того, где они определены. Поставьте обратную косую черту ("\") перед первым "!" для шаблонов, которые начинаются с буквального «!», например, "! Важно! .Txt".

Если шаблон заканчивается косой чертой, он удаляется с целью последующее описание, но он найдет совпадение только с каталог. Другими словами, foo / будет соответствовать каталогу foo и путям под ним, но не будет соответствовать обычному файлу или символической ссылке foo (это согласуется с тем, как вообще работает pathspec в Git).

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

/path/to/git/repo
|-- .gitignore
|-- /cache
    |-- somefile
    |-- README    
    |-- /dir
        |-- somefile2
        |-- README

И мы хотим игнорировать все файлы внутри кэша / кроме файлов README.

Если мы укажем gitignore следующим образом:

/cache/**
!README

Git будет игнорировать все, кроме /cache/README. Другой README не будет отображаться, потому что его каталог /cache/dir был исключен с /cache/** и !README даже не будет применяться к нему. Чтобы решить эту проблему, нам нужно указать gitignore следующим образом:

# Ignore everything inside cache/ dir
/cache/**
# Except for subdirectories(won't be commited anyway if there is no commited file inside)
!/cache/**/
# And except for README files
!README
...