.gitignore белый список в каталоге и его содержимое
Я пытаюсь перечислить каталог (и его содержимое) в списке поставщиков в каталоге Zend Framework 2.
Оригинальный файл .gitignore в /vendor выглядит следующим образом:
# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
!.gitignore
*
Теперь я хотел бы добавить белый список в каталог SupplierName, который не должен быть слишком сложным, я думал. Я прочитал документы о gitignore и попробовал следующие конфигурации:
Сначала попробуйте, добавьте! SupplierName сразу после комментария, в котором говорится, что я должен добавить туда белый путь.
# Add here the vendor path to be whitelisted
!SupplierName
# Ex: for composer directory write here "!composer" (without quotes)
!.gitignore
*
Сразу после этого я выполнил git status
, который не показывал каталог vendor/SupplierName. git add vendor/SupplierName
отобразилось следующее сообщение:
Следующие пути игнорируются одним из ваших файлов .gitignore: vendor/SupplierName
Вторая попытка
# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
!SupplierName
!.gitignore
*
Сразу после этого я выполнил git status
, который не показывал каталог vendor/SupplierName. git add vendor/SupplierName
отобразилось следующее сообщение:
Следующие пути игнорируются одним из ваших файлов .gitignore: vendor/SupplierName
Третья попытка
# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
!.gitignore
*
!SupplierName
Сразу после этого я выполнил git status
, который не показывал каталог vendor/SupplierName. git add vendor/SupplierName
, похоже, работает. Но теперь, когда я хочу добавить файл Module.php(и некоторые другие файлы, подкаталоги и т.д.), Произойдет следующее. git add vendor/SupplierName/Module.php
→
Следующие пути игнорируются одним из ваших файлов .gitignore: vendor/SupplierName/Module.php
# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
*
!.gitignore
!SupplierName
!SupplierName/
!SupplierName/*
Позволяет мне добавлять файлы непосредственно в vendor/SupplierName, но git add vendor/SupplierName/config/module.config.php
все еще приводит к
Следующие пути игнорируются одним из ваших файлов .gitignore: vendor/SupplierName/config/module.config.php
Я искал проблемы с рекурсивным "белым списком", потому что это проблема, но ничего не получилось.
Ответы
Ответ 1
Вы можете использовать 2 .gitignore
файлы для достижения желаемого результата:
# vendor/.gitignore
*
!.gitignore
!SupplierName/
!SupplierName/*
# vendor/SupplierName/.gitignore
!*
Я тестировал это с помощью тестового репо и, похоже, работал у меня в добавлении файлов на столько уровней, которые находятся под каталогом vendor/SupplierName
.
$ git add .
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: vendor/.gitignore
# new file: vendor/SupplierName/.gitignore
# new file: vendor/SupplierName/a
# new file: vendor/SupplierName/b
# new file: vendor/SupplierName/c
# new file: vendor/SupplierName/d
# new file: vendor/SupplierName/dir1/d
# new file: vendor/SupplierName/dir1/dir4/dir5/dir6/dir7/dir8/dir9/dir10/somefile
# new file: vendor/SupplierName/dir1/dir4/f1
# new file: vendor/SupplierName/dir1/dir4/f2
# new file: vendor/SupplierName/dir1/dir4/f3
# new file: vendor/SupplierName/dir1/dir4/f4
# new file: vendor/SupplierName/dir1/e
# new file: vendor/SupplierName/dir1/f
# new file: vendor/SupplierName/dir3/dir6/f5
# new file: vendor/SupplierName/dir3/dir6/f6
# new file: vendor/SupplierName/dir3/dir6/f7
# new file: vendor/SupplierName/dir3/dir7/f8
# new file: vendor/SupplierName/e
#
Ответ 2
Вы также можете добиться этого только одним файлом .gitignore
(в корне вашего проекта):
/*
!/.gitignore
!/vendor
/vendor/*
!/vendor/SupplierName
Ответ 3
Нашла интересную статью: https://jasonstitt.com/gitignore-whitelisting-patterns
Все кредиты Джейсону Ститту. Тексты копируются с сайта выше:
Игнорировать все, а затем добавить определенные поддеревья
# Ignore everything
*
# But descend into directories
!*/
# Recursively allow files under subtree
!/subtree/**
# You can be specific with these rules
!/some/other/deep/path/**
!.gitignore
Правило !*/
игнорирует все каталоги. Но Git не отслеживает каталоги, только файлы, поэтому !*/
сам по себе будет разрешить спуск в полное дерево каталогов; он фактически не позволит ничего в репо. При наличии этого правила вам потребуется только один с использованием рекурсивного подстановочного символа **
, чтобы включить поддерево.
Если вы не использовали !*/
, вам понадобятся дополнительные правила, чтобы игнорировать /поддерево и его дочерние каталоги.
Не всем нравится !*/
, потому что это означает, что если какое-либо другое правило позволяет создать шаблон имени файла внутри какой-либо директории, которую вы не хотите в репо, сама директория не будет заблокирована. Вы должны использовать специальные правила для файлов, которые должны быть включены с этим.
Игнорировать корневой каталог, затем добавить целые поддеревья
# Ignore everything in the root
/*
# Un-ignore all of subtree
!/subtree/
!.gitignore
Этот шаблон несколько грубее, чем предыдущий. Правило /*
будет игнорировать элементы в корне репозитория структуру каталогов, поэтому, как только вы перейдете в белый список из каталога, все содержимое каталогов также будет разрешено, даже без использования подстановочные знаки *
или **
.
Игнорировать все в каталоге, но сохранить пустую директорию
*
!.gitignore
Git не хочет включать пустой пул в репо, потому что он отслеживает файлы. Поместите скрытый файл (например, .gitignore) в каталог, и он будет сохранен. Но чтобы сохранить каталог пустым, даже если у вас есть файлы для тестирования/разработки, хорошая идея игнорировать все, кроме самого файла .gitignore.
Ответ 4
У меня была аналогичная проблема при переходе с CVS на Git.
В отличие от CVS, Git не смотрит на каталоги, он фокусируется на файлах.
Например, вы не можете игнорировать каталог "a" , но вы не можете игнорировать все файлы в каталоге "a" так:! a/*
То же самое верно для подкаталогов.
Если в каталоге "a" есть подкаталог "b", и вы игнорируете "! a/*", тогда вы все равно получите все файлы в "a/b".
Таким образом, вы должны игнорировать это слишком "! a/b/*" и т.д. для всех подкаталогов, которые вы хотите иметь в белом списке.
Вам нужен только один файл .gitignore.
чтобы вы получили что-то вроде:
# ignore everything
*
# except for .gitignore files in the current directory
!.gitignore
# and all files in directory a
!a/*
#and all files in subdirectory b
!a/b/*
С этим вы все равно получите файлы из a/c и a/b/c. Я не уверен, есть ли временное решение для рекурсии вниз подкаталогов.
Ответ 5
Сначала вы должны включить все в черный список, а затем сделать все каталоги и субтитры в белом списке.
Например, я хочу только добавить DIR /opt/source/
, DIR /opt/nginx/
и FILE /home/test/.opt/hello.txt
в белый список, написать файл .gitignore
, как это сделать, чтобы он работал:
/*
!/.gitignore
!/opt
/opt/*
!/opt/source/
!/opt/nginx/
!/home
/home/*
!/home/test
/home/test/*
!/home/test/.opt
/home/test/.opt/*
!/home/test/.opt/hello.txt
Ответ 6
Я создал простой JS-фрагмент кода, который можно запустить в Node для генерации правила белого списка, так как я нашел, что написание правил вручную немного сбивает с толку, и я хотел иметь возможность изменить правило позже, если забыл, как его написать вручную.
'use strict';
// Generating a "whitelist" wherein you only want a specific folder to be
// affected requires following .gitignore-style rules.
// https://github.com/prettier/prettier/issues/3328
//
// Handcrafting these rules is hard to reason about and error-prone, so I'm
// going to generate them.
// See: https://github.com/prettier/prettier/issues/3328
// And: https://git-scm.com/docs/gitignore
//
const path = require('path');
const whitelistDir = '/themes/simple/src/';
function generateIgnoreRule(dir) {
let output = '# Auto-generated by ' + path.basename(__filename) + '\n';
output += '# Exclude everything except '' + dir + ''\n';
// Add exclude everything rule
output += '/*' + '\n';
// Split by path
const parts = dir.split('/');
if (parts[0] === '') {
// Remove first item if its blank
parts.shift();
}
if (parts[parts.length - 1] === '') {
// Remove last item if its blank
parts.pop();
}
let totalPart = '';
for (let part of parts) {
totalPart += '/' + part;
output += '!' + totalPart + '\n';
if (part !== parts[parts.length - 1]) {
output += totalPart + '/*' + '\n';
}
}
return output;
}
console.log(generateIgnoreRule(whitelistDir));
console.log(
'\nCopy the above rules out of the console output and paste into your .gitignore / .prettierignore'
);
Ответ 7
Это связано с первым методом @Simon Lang (с благодарностью Jason Stitt), но применимо к более широкому кругу случаев.
Предположим, что вы хотите иметь только один .gitignore в корне вашего проекта, и предположим, что вы хотите игнорировать большую часть некоторого подкаталога вашего проекта, но разрешить небольшую часть. Например, предположим, что в вашем репозитории есть каталог /vendor/
со сторонней зависимостью, который вы решили сохранить в значительной степени нетронутым, но в который вы внесете некоторые легкие корректировки, которые вы хотите отслеживать в git, возможно, для помощи в обратном портировании когда появляется неизбежная новая версия.
Затем вы можете сделать следующее в своем корневом файле .gitignore
:
# ignore all files and folders in '/vendor/' and in its descendants
/vendor/**
# negated pattern to un-exclude all *folders* at any depth relative to 'vendor/'
# as always git will ultimately ignore the folders for which you don't
# subsequently un-exclude any *files*.
!/vendor/**/
# negated pattern to un-exclude all files and folders at any depth below the deep
# path that contains files you want in git
!/vendor/supplier/version/module/component/src/**
Каждый экземпляр двойной звездочки имеет решающее значение. Например, конечный vendor/**
сопоставляет все внутри - все файлы и каталоги в vendor
с бесконечной глубиной, и поэтому исключает всех его потомков.
В "нормальном" подстановочном правиле gitignore, таком как *.exe
или *
, сопоставление метасимвола глобуса обнаруживает любой файл в любом каталоге, поскольку путь является неограниченным. Неограниченный путь делает здесь тяжелую работу, а не расширение подстановочного знака. Как только вы попытаетесь ограничить область действия игнорирования подкаталогом своего корня, этот тяжеловес исчезнет, и вы сразу же натолкнетесь на неспособность *
спуститься в дерево.
Ответ саймона работает, оставляя кончик исходного пути исключения без ограничений. Изначально он исключает каждый файл (на любой глубине) в каталоге, который содержит файл .gitignore. Мой дает вам гибкость в применении этого подхода исключить все к подкаталогам, используя **
для сопоставления глобстар /
. Вы можете добиться того же эффекта, имея несколько файлов .gitignore и используя технику Саймона в файле .gitignore, расположенном в /vendor/.gitignore
, но это больше для поддержки.
Я не знаю, есть ли какие-либо последствия для производительности при использовании **
, как я сделал здесь. Это можно проверить, сравнив производительность .gitignore, которая выглядела как
*
!*/
!a/b/c/d/**
тому, который был похож на это
/**
!**/
!a/b/c/d/**
в дереве, имеющем много файлов. Я считаю, что один и тот же контент будет включен и исключен, но реализация под капотом может отличаться, как и производительность.