Как на самом деле работают правила исключения .gitignore?

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

У меня есть следующая структура каталогов из двух файлов (foo, bar) в новом репозитории git (до сих пор не зафиксировано):

a/b/c/foo
a/b/c/bar

Очевидно, что статус 'git -u' показывает:

# Untracked files:
...
#       a/b/c/bar
#       a/b/c/foo

Я хочу создать файл .gitignore, который игнорирует все внутри a/b/c, но не игнорирует файл 'foo'.

Если я создаю .gitignore таким образом:

c/

Тогда статус 'git -u' показывает как foo, так и bar как игнорируемые:

# Untracked files:
...
#       .gitignore

Что, как я ожидаю.

Теперь, если я добавлю правило исключения для foo, таким образом:

c/
!foo

Согласно man-странице gitignore, я ожидаю, что это сработает. Но это не так - он все еще игнорирует foo:

# Untracked files:
...
#       .gitignore

Это также не работает:

c/
!a/b/c/foo

Также это:

c/*
!foo

дает:

# Untracked files:
...
#       .gitignore
#       a/b/c/bar
#       a/b/c/foo

В этом случае, хотя foo больше не игнорируется, bar также не игнорируется.

Порядок правил в .gitignore тоже не имеет значения.

Это также не делает то, что я ожидаю:

a/b/c/
!a/b/c/foo

Это игнорирует как foo, так и bar.

Одна из ситуаций, которая работает, - это создать файл a/b/c/ .gitignore и поставить там:

*
!foo

Но проблема в том, что в конечном итоге будут другие подкаталоги под a/b/c, и я не хочу включать отдельный .gitignore в каждый из них - я надеялся создать "проект- основанные на файлах .gitignore, которые могут находиться в верхней директории каждого проекта и охватывать все стандартные структуры подкаталогов.

Это также кажется эквивалентным:

a/b/c/*
!a/b/c/foo

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

В любом случае, я не совсем понимаю, как работают правила исключения, или они вообще не работают, когда игнорируются каталоги (а не подстановочные знаки) - по правилу, заканчивающемуся в /

Кто-нибудь может пролить свет на это?

Есть ли способ заставить gitignore использовать что-то разумное, как регулярные выражения вместо этого неуклюжего синтаксиса на основе оболочки?

Я использую и наблюдаю это с помощью git -1.6.6.1 на Cygwin/bash3 и git -1.7.1 на Ubuntu/bash3.

Ответ 1

/a/b/c/*
!foo

Кажется, работает для меня (git 1.7.0.4 на Linux). * важен, поскольку в противном случае вы игнорируете сам каталог (поэтому git не будет выглядеть внутри) вместо файлов в каталоге (что позволяет исключить).

Подумайте об исключениях как о "но не об этом", а не "но включите это" - "игнорировать этот каталог (/a/b/c/), но не этот (foo)" не имеет большого смысла; msgstr "игнорировать все файлы в этом каталоге (/a/b/c/*), но не этот (foo)". Чтобы процитировать страницу man:

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

i.e, файл должен быть исключен уже для включения снова. Надеюсь, что проливает свет.

Ответ 2

У меня похожая ситуация, мое решение заключалось в использовании:

/a/**/*
!/a/**/foo

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

Ответ 3

Вот еще один вариант:

*
!/a*
!/a/*
!/a/*/*
!/a/*/*/*

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

Ответ 4

это определенно не понятно из справочной страницы .gitignore. Это работает:

*
!/a
!/a/b
!/a/b/c
!/a/b/c/foo

# don't forget this one
!.gitignore

Как упоминалось Крисом, директория даже не открывается, если она исключена. Поэтому, если вы хотите игнорировать *, но некоторые файлы, вы должны создать путь к тем файлам, как указано выше. Для меня это удобно, потому что я хочу сделать обзор кода в 1 файле библиотеки, и если я хочу сделать другое позже, просто добавлю его, а все остальное будет проигнорировано.

Ответ 5

В более общем случае git1.8.2 будет включать патч (также в своем v4, , вызванный некоторым вопросом) от Adam Spiers об определении того, какое правило gitignore фактически игнорирует ваш файл.

Смотрите примечания к выпуску git1.8.2 и вопрос SO , в котором правило gitignore игнорирует мои файл ":
это будет команда git check-ignore.