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

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

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

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

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

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

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

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

c/

Затем 'git status -u' показывает foo и bar как игнорируемые:

# Untracked files:
...
#       .gitignore

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

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

c/
!foo

Согласно руководству 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

Но проблема в том, что со временем в /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.

5 ответов

Решение
/ A / B / C /*! Foo

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

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

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

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

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

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

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

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

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

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

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

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

# don't forget this one
!.gitignore

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

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

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

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