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

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

пример

/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 ответа

Решение

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

*
!*/
!.gitignore
!layout.css

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

Дело в том, что пока вы не можете зафиксировать пустые каталоги в 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 не выводит список исключенных каталогов по соображениям производительности, поэтому любые шаблоны для содержащихся файлов не влияют, независимо от того, где они определены. Поставьте обратную косую черту ("\") перед первым "!" для шаблонов, которые начинаются с литерала "!", например, "! Important!.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

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

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

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

Другие вопросы по тегам