Как отрицать шаблон gitignore, содержащий пробелы?

Вопрос или проблема

Мой .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 требует понимания порядка выполнения правил и их синтаксиса, особенно когда названия содержат пробелы. Следуя описанным рекомендациям и тщательно формулируя свои исключения, вы сможете успешно включить необходимые директории и файлы в ваш репозиторий, избегая нежелательного игнорирования.

Оцените материал
Добавить комментарий

Капча загружается...