Отменить игнорирование подкаталогов игнорируемых каталогов в Git

100

Скажем, я проигнорировал каталог, но хочу отменить игнорирование определенных подкаталогов в нем. Итак, у меня есть настройка:

/uploads/
/uploads/rubbish/
/uploads/rubbish/stuff/KEEP_ME/
/uploads/foo/
/uploads/foo/bar/lose/

И я хочу игнорировать все, кроме KEEP_MEкаталога. Я надеюсь, что игнорирование будет выглядеть примерно так:

/uploads/*
!/uploads/rubbish/stuff/KEEP_ME/

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

Тот, который действительно работает,

/uploads/**/**/**/
!/uploads/rubbish/stuff/KEEP_ME/

Но это кажется немного ограничительным и многословным?

Wil
источник
1
Предоставленный вами код не работал у меня (с использованием git версии 1.9.1). Сработал / uploads / *! / Uploads / rubbish / / uploads / rubbish / *! / Uploads / rubbish / stuff / uploads / rubbish / stuff / *! / Uploads / rubbish / stuff / keep (аналогично примеру в git-scm.com/docs/gitignore ). Моя структура папки; └ README.md └ uploads / foo / bar / lost / lost.txt └ uploads / rubbish / stuff / keep / keep.txt
gihanchanuka

Ответы:

119

Согласно разделу формата шаблона документации gitignore :

Необязательный префикс "!" который сводит на нет узор; любой соответствующий файл, исключенный предыдущим шаблоном, снова будет включен. Невозможно повторно включить файл, если родительский каталог этого файла исключен. Git не перечисляет исключенные каталоги по соображениям производительности, поэтому любые шаблоны для содержащихся файлов не имеют никакого эффекта, независимо от того, где они определены. Поставьте обратную косую черту ("\") перед первым "!" для шаблонов, начинающихся с буквального символа «!», например «! important! .txt».

Следовательно, ранее исключенный /uploads/rubbish/stuff/keep/шаблон родительского каталога должен быть исключен исключительно перед отрицанием его содержимого:

#ignore everything within /uploads/ 
/uploads/*

#include everything within /uploads/rubbish/stuff/keep
!/uploads/rubbish/stuff/keep/  
!/uploads/rubbish/stuff/keep/*

Чтобы включить подкаталоги внутрь, /uploads/rubbish/stuff/keep/добавьте третью строку:

!/uploads/rubbish/stuff/keep/**/*
Арт Шайдеров
источник
1
Какую версию git вы использовали? Возможно, это что-то доступно только в определенных версиях.
Смущенный. Я забыл, что опубликовал этот комментарий. Но у меня все заработало. FWIW, я не использую ведущие косые черты. Я не помню, была ли это проблема. Я использую 1.7.2.5.
У меня есть глобальный файл gitignore, в котором я проигнорировал все файлы * .zip. Тем не менее, для конкретного проекта я хочу включить zip-файлы. Я добавил эту строчку к этому проекту, .gitignoreи она отлично работает !:!*.zip
Цзинхао Ши,
Я счел необходимым явно указать произвольные каталоги как до, так и после данной папки, как при исключении папки, так и при включении подпапки . ( Полный ответ ).
Josiah Yoder
Этот метод не работает (начиная с git 2.25 - возможно, что-то в git изменилось). Я разместил stackoverflow.com/a/60288435/295691 ниже в качестве исправления.
user295691
34

Даже если вы что-то добавляете .gitignore, вы можете заставить git добавить это в индекс

git add --force uploads/rubbish/stuff/KEEP_ME/

Однако «KEEP_ME» кажется каталогом, и git обычно не любит пустую папку, поэтому вы можете вместо этого добавить файл «заполнитель», если папка пуста.

git add --force uploads/rubbish/stuff/KEEP_ME/.keep_me
KingCrunch
источник
Единственная проблема в том, что этот конкретный пример относится к глобальному gitignore, о котором я должен был упомянуть. Я знаю, что могу принудительно добавлять элементы, но мне придется это делать, если будут добавлены какие-либо новые элементы, а также сначала для каждого нового репозитория. Гарантирует ли .keep, что содержимое не игнорируется?
Wil
1
Сделал небольшой тест. Да, вы должны использовать git add --forceдля каждого нового элемента или папки в KEEP_ME. но после этого обновления просто добавляются (например, при выполнении a git add -u), как если бы файлы «не игнорировались». Он .keep_meничего не делает, это просто файл, так что git работает с папкой.
commonpike
1
git add --forceэто неправильное решение. Если вы переместите каталог или переместите файл в другой каталог, отслеживание git удалит файл, но не добавит его в новое место, и вам придется сделать это git add --forceснова. Отказавшись от общего шаблона, git будет отслеживать перемещение файла в репозитории.
Мерлин
Это единственное решение, которое у меня сработало. Моя папка НЕ ​​игнорировалась, но я никак не мог ее добавить. Таким образом я решил эту проблему.
Акито
6

Пытался выяснить, как включить конкретную папку при исключении всех папок с общим исключением

**/build

если вы добавите /* конец своего универсального исключения, вы продолжите исключать все файлы сборки**/build/*

Затем вы добавляете еще одну строку, чтобы исправить путь, который вы хотите включить, чтобы он выглядел

!**/folder/build/* 

оставив нам gitignore, который читает

**/build/* 
!**/folder/build/* 
Джон
источник
3

Буо-Рен Линь и ДжонОтветы очень полезны, но мне нужно было объединить оба.

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

**/uploads/*
!**/uploads/rubbish/
!**/uploads/rubbish/*

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

Джозайя Йодер
источник
Вздох. Здесь нулевая удача. На это уже несколько часов. Git 2.20.1
RichieHH
@ HörmannHH Сожалеем об этом. Может, пора задать новый вопрос?
Джозайя Йодер,
2

Решение, представленное как ответ, получившее наибольшее количество голосов, неверно и легко демонстрируется как таковое.

Начните с игнорирования всего в uploads / *:

mkdir -p uploads/rubbish/stuff/KEEP_ME
touch uploads/a uploads/rubbish/a uploads/rubbish/stuff/a uploads/rubbish/stuff/KEEP_ME/a
echo '/uploads/*' >> .gitignore
git init
git add .
git commit -m "Initial commit"

Теперь отмените игнорирование родительского каталога игнорируемого материала, как указано выше:

echo 'uploads/rubbish/stuff/KEEP_ME/' >> .gitignore
echo 'uploads/rubbish/stuff/KEEP_ME/*' >> .gitignore
git status -u

Не показывает неотслеживаемые файлы.

Чтобы заставить его работать, вам нужно игнорировать все файлы в uploads/дереве (а uploads/**/*не только на верхнем уровне uploads/*), а затем добавить все родительские каталоги дерева, которое вы хотите сохранить.

echo '/uploads/**/*' > .gitignore
echo '!/uploads/rubbish/' >> .gitignore
echo '!/uploads/rubbish/stuff' >> .gitignore
echo '!/uploads/rubbish/stuff/KEEP_ME' >> .gitignore
echo '!/uploads/rubbish/stuff/KEEP_ME/*' >> .gitignore
git status -u

Который дает:

On branch master
...
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        uploads/rubbish/stuff/KEEP_ME/a

Если бы мы использовали uploads/*в .gitignoreвыше, то все промежуточные файлы были бы включены, так что , например , uploads/rubbish/aбудет отображаться в команде статус выше.

user295691
источник