Комментарий iBug имеет один из ключей к выполнению этой работы. Другой - убедиться, что файл не отслежен .
Неотслеживаемые файлы - это файлы, которых нет в индексе
Индекс , также называемый промежуточной областью или иногда кеш , определяет, отслеживается ли файл или нет. Индекс также используется Git при создании новых коммитов, поэтому каждый файл в индексе попадает в следующий коммит, который вы делаете, когда вы его делаете. Чтобы увидеть список каждого файла в индексе вместе с его промежуточной информацией, используйте git ls-files --stage
(обратите внимание, что это может быть очень длинный список!): Пути к файлам появляются в конце каждой строки вывода.
Git сообщает о неотслеживаемом файле , когда в процессе сканирования через каталог он сталкивается с файлом, путь к которому (a) еще не указан в индексе и (b) не указан в игнорировать или исключать файл. (Здесь есть специальная обработка для каталогов, но давайте оставим это на потом.)
Другими словами, любой файл в индексе отслеживается . Файл, который не в индексе, не отслеживается, и некоторые неотслеживаемые файлы также игнорируются. Важно отметить, что отслеживаемый файл никогда не игнорируется.
Имена путей - это строки UTF-8
Для файлов с простыми именами в стиле ASCII , таких как README.txt
или Documentation/RelNotes/2.9.5.txt
, имя пути довольно очевидно. Он кодируется в виде строки байтов: R
в README
или RelNotes
- это байт со значением 82 (в любом случае в десятичном виде: это 0x52 в шестнадцатеричном или 0122 в восьмеричном). Но для других символов, таких как ö in schön или é in agréable, или, конечно, ваш 예제 파일 (который я должен был вырезать и вставить здесь :-)), существует проблема с кодировкой.
Git выбирает при условии , что все имена файлов закодированы в UTF-8 . Ваша операционная система может выбрать другую кодировку для внутреннего использования - например, Windows использует UTF-16 в ряде своих файловых систем - но Git предполагает UTF-8, который имеет многочисленные преимущества, в том числе не требует маркера порядка байтов (BOM),. Это не решает всех проблем - все еще есть проблемы с нормализацией - но указывает нам ответ, который мы хотим для .gitignore
файлов.
(Git также использует эту форму UTF-8 в индексе.)
Когда Git читает файл .gitignore
, он открывает его как поток байтов , который должен содержать кодировку UTF-8 для каждого имени файла, оканчивающегося символом новой строки. Затем, когда Git отправляется на чтение каталога для извлечения имен файлов (или подкаталогов) из операционной системы, Git преобразует эти имена в строки UTF-8. Если эти имена файлов представляют собой неотслеживаемых файлов, Git будет сравнивать результирующие строки UTF-8 со строками в кодировке UTF-8 в каждой строке в файле .gitignore
.
Если строки в кодировке UTF-8 совпадают, имя неотслеживаемого файла игнорируется (или игнорируется, если префикс !
, поскольку, конечно, применяются все обычные правила ).
Если содержимое файла .gitignore
не является строками в кодировке UTF-8, попытка игнорировать не удастся, поскольку представление 예제 파일 в UTF-8 (например, b'\xec\x98\x88\xec\xa0\x9c\xed\x8c\x8c\xec\x9d\xbc'
в Python) не будет совпадать с UTF-16LE представление тех же символов:
>>> fn = b'\xec\x98\x88\xec\xa0\x9c\xed\x8c\x8c\xec\x9d\xbc'
>>> fn
b'\xec\x98\x88\xec\xa0\x9c\xed\x8c\x8c\xec\x9d\xbc'
>>> fn.decode('utf-8')
'예제파일'
>>> fn.decode('utf-8').encode('utf-16le')
b'\x08\xc6\x1c\xc8\x0c\xd3|\xc7'
Примечание: каталоги и файлы
Git хранит только файлов в репозитории. Это создает некоторую напряженность между каталогами, которые должны существовать для хранения файлов, и самими файлами. Одним из побочных эффектов является то, что вы не можете хранить каталог empty в коммите Git (см. Как добавить пустой каталог в репозиторий Git? ), но другой предлагает используя .gitignore
.
Вид операционной системыДля поиска файлов обычно требуется начать с поиска в каталоге (или «папке», если вы предпочитаете эту метафору). Этот каталог имеет имя внутри файловой системы. Git откроет каталог по имени и прочитает его содержимое, по одной записи за раз. Каждая запись будет содержать либо имя файла, либо имя другого каталога. Git может проверять каждое такое имя файла - после объединения его с именем родительского каталога и косой черты, например, давая dir/README.txt
- по индексу (чтобы увидеть, отслеживается ли он), а затем, если не отслеживается, по всем спискам игнорирования ( чтобы увидеть, должен ли Git жаловаться на это или игнорировать его).
Но поиск внутри каталога относительно медленный. Предположим, что Git имеет путь типа a/b/c/d
, который представляет каталог. Git может и сначала просматривает индекс, чтобы увидеть, есть ли какие-либо файлы, уже отслеженные в a/b/c/d
. Если это так, Git должен прочитать каталог. Но если нет, Git теперь может проверить все списки игнорирования, чтобы увидеть, игнорируется ли a/b/c/d
сам .
Если a/b/c/d
игнорируется , Git не вынужден читать его содержимое! Если в a/b/c/d
есть миллионы файлов - в подкаталогах или нет - это экономит время. Так что Git тоже это делает. Если Git никогда не заглядывает внутрь a/b/c/d
, он никогда не найдет никаких неотслеживаемых файлов внутри a/b/c/d
. Вот почему вы должны явно игнорировать каталоги в некоторых случаях: заставить Git искать внутри их для неотслеживаемых файлов.
(Можно подумать, что это перечисление в .gitignore
, что-то вроде:
a/b/c/d
!a/b/c/d/e/important.file
было бы достаточно, чтобы сказать Git: да, игнорировать все в a/b/c/d
, но по-прежнему заглядывать внутрь d
для d/e
и впоследствии d/e/important.file
, так как вы будете придется заглянуть внутрь него, чтобы игнорировать такой файл. И Git может стать таким умным в какой-то момент, но исторически это не так. Таким образом, правило для этого состоит в том, чтобы перечислить это как:
a/b/c/d/*
!a/b/c/d/e
a/b/c/d/e/*
!a/b/c/d/e/important.file
, которое переопределяет правило "игнорировать все" для a/b/c/d/e
: a/b/c/d
само по себе не игнорируется, поэтому Git открывает и читает его. Тогда a/b/c/d/<em>any</em>
игнорируется , если any явно e
, что не игнорируется. Итак, Git открывает a/b/c/d/e
и читает его. Все в a/b/c/d/e
игнорируется, кроме important.file
.)