Вопрос или проблема
Мой .gitignore начинается с исключения всего, а затем отменяет исключение всего, что я хочу включить, чтобы избежать большого количества мусора в git status
:
*
!awesome/
!calibre/
[…]
Однако после установки Visual Studio Code я не могу, похоже, отменить матч для директории “Code – OSS”. Я пробовал следующие строки:
!Code - OSS/
!Code\ -\ OSS/
!'Code - OSS/'
!"Code - OSS/"
!Code*
Со всеми этими строками в конце моего .gitignore git status
все равно не показывает эту директорию как доступную для включения.
Вывод git check-ignore --verbose Code\ -\ OSS
с каждой из этих строк также странный:
.config/.gitignore:22:!Code - OSS/ Code - OSS
.config/.gitignore:22:!Code\ -\ OSS/ Code - OSS
.config/.gitignore:1:* Code - OSS
.config/.gitignore:1:* Code - OSS
.config/.gitignore:22:!Code* Code - OSS
Эта проблема не связана с тем, что директория имеет пробелы в своем названии. Страница man по gitignore(5) не содержит никаких специальных правил, связанных с пробелами, за исключением этого:
Пробелы в конце игнорируются, если они не заключены в кавычки с помощью обратной косой черты (“\”).
Что касается того, почему переопределение !foo bar/
кажется, не учитывается, посмотрите последний пример на странице man по gitignore(5):
Пример, чтобы исключить все, кроме конкретной директории foo/bar (обратите внимание на /* – без косой черты, подстановочный знак также исключит все внутри foo/bar):
$ cat .gitignore # исключить все, кроме директории foo/bar /* !/foo /foo/* !/foo/bar
Это поведение /* объясняется в разделе Формат шаблона:
Если в начале или середине (или в обоих) шаблона есть разделитель, то шаблон относителен к уровню директории конкретного .gitignore файла. В противном случае шаблон может также соответствовать любому уровню ниже уровня .gitignore.
Так что *
отменяет любое переопределение !foo bar/
, потому что он совпадает с любыми файлами и директориями в любом месте в иерархии директорий ниже корня репозитория. Точная строка !foo bar/
только отменяет игнорирование директории foo bar, и любых файлов и директорий внутри нее, которые не соответствуют никаким предыдущим применимым паттернам игнорирования:
$ cat .gitignore
foo*
!foo bar/
$ ls -lR
.:
total 8
drwxr-xr-x 2 user user 512 May 11 11:10 foo/
drwxr-xr-x 3 user user 512 May 11 10:51 foo bar/
-rw-r--r-- 1 user user 0 May 11 09:05 gar
./foo:
total 0
-rw-r--r-- 1 user user 0 May 11 11:10 test
./foo bar:
total 4
drwxr-xr-x 2 user user 512 May 11 10:51 baz/
-rw-r--r-- 1 user user 0 May 11 08:24 blur
-rw-r--r-- 1 user user 0 May 11 11:28 foo
./foo bar/baz:
total 0
-rw-r--r-- 1 user user 0 May 11 10:51 goo
$ git add -A
$ git status --short
A .gitignore
A "foo bar/baz/goo"
A "foo bar/blur"
A gar
Обратите внимание, что хотя директория foo bar исключена из игнорирования, файл foo внутри нее не является (он не проиндексирован)!
В вашем примере попробуйте, например, добавить !foo bar/**
(иерархия директорий такая же, как в предыдущем примере):
$ cat .gitignore
*
!foo bar/
!foo bar/**
$ git status --short
?? "foo bar/"
Похоже, это ошибка. Тестовый случай:
$ cd "$(mktemp --directory)"
$ mkdir foo\ bar
$ touch foo\ bar/test
$ git init
Initialized empty Git repository in /tmp/tmp.iGmBR6y2xR/.git/
$ git status --short
?? foo bar/
$ cat > .gitignore << EOF
> *
> !foo bar
> !foo\ bar
> !"foo bar"
> "!foo bar"
> !foo bar/
> !foo\ bar/
> !"foo bar/"
> "!foo bar/"
> EOF
$ git status --short
[no output]
Обходное решение/контратестовый случай:
$ cat > .gitignore << EOF
> */
> !foo\ bar/
> EOF
$ git status --short
?? .gitignore
?? foo bar/
Ответ или решение
Когда дело доходит до управления исключениями в файле .gitignore
, важно понимать, как Git интерпретирует шаблоны, особенно в случае, если названия директорий или файлов содержат пробелы. Ваша проблема заключается в том, чтобы правильно отменить игнорирование директории с пробелами в названии, а именно "Code – OSS".
Причины проблемы
Как уже упомянуто, файл .gitignore
в начале исключает все (*
), и последующие строки предназначены для отмены игнорирования конкретных директорий или файлов. Однако, когда вы используете *
, это правило применяется ко всем файлам и директориям, включая те, что вы пытаетесь включить обратно с помощью команд вида !Code - OSS/
. В данном случае *
имеет более высокий приоритет, что приводит к тому, что Git не видит ваши исключения.
Правильное решение
Чтобы корректно отменить игнорирование директории "Code – OSS", вам необходимо воспользоваться другой моделью написания правил в .gitignore
. Например, вы можете использовать следующий подход:
/*
!Code\ -\ OSS/
Или же, в зависимости от вашей структуры каталогов и того, где расположен .gitignore
, вы можете создать более конкретные правила:
/*
!/Code - OSS/
Обратите внимание, что использование обратной косой черты (\
) позволяет вам экранировать пробелы, делая их частью имени.
Также можно использовать строку с двумя звёздочками для инклюзии всех содержимого в директории:
!Code - OSS/**
Этот подход гарантирует, что не только сама директория, но и все содержимое в ней включается в отслеживаемые файлы Git.
Проверка правила
Для проверки правильности работы ваших правил используйте команду:
git check-ignore -v Code\ -\ OSS/
Это покажет, какие правила применяются к этой директории и поможет вам диагностировать, если она все еще по-прежнему игнорируется.
Пример использования
Предположим, у вас есть следующая структура каталогов:
/
└── .gitignore
└── Code - OSS/
└── somefile.txt
Ваше .gitignore
может выглядеть следующим образом:
/*
!Code\ -\ OSS/
!Code - OSS/**
После добавления и изменения вашего файла .gitignore
выполните git add -A
и git status
. Это должно показать подготавливаемые к коммиту изменения.
Заключение
Управление файлами в Git при использовании .gitignore
требует понимания порядка выполнения правил и их синтаксиса, особенно когда названия содержат пробелы. Следуя описанным рекомендациям и тщательно формулируя свои исключения, вы сможете успешно включить необходимые директории и файлы в ваш репозиторий, избегая нежелательного игнорирования.