TL; DR
Как отметили комментаторы, файл должен иметь имя .gitignore
, а не .gitignore.txt
.
Реальный ключ для понимания .gitignore
записей, однако, понять Git х индекс . Если вы не знаете об индексе и о том, как Git использует его, некоторые вещи будут очень загадочными.
Файл, который находится в вашем рабочем дереве, но отсутствует в индексе Git, является неотслеживаемый файл . Перечисление имени неотслеживаемого файла или шаблона, соответствующего его имени, в файле .gitignore
сообщает git status
to shutdown об этом - не вызывать его как неотслеживаемое, а также предотвращает git add
от копирования файла в индекс Git. Если файл равен в индексе Git, то перечисление имени файла в .gitignore
не влияет на сохранение файла Git.
Long
Первое, что нужно понять, это то, что Git не столько о файлах или ветвях: Git - это все о commits . Каждый коммит хранит полный и полный снимок всех ваших файлов - или, по крайней мере, всех тех, что вы указываете на снимок. Как только коммит сделан, он замораживается навсегда. Этот коммит, идентифицируемый его уникальным идентификатором ha sh - большой уродливой строкой букв и цифр, например, 9fadedd637b312089337d73c3ed8447e9f0aa775
- всегда будет содержать именно эти файлы плюс метаданные о том, кто сделал совершать, когда и так далее. Они хранятся в специальном, только для чтения, Git -только формате, который может понять только Git.
Второе, что нужно понять, так это то, что файлы, хранящиеся в коммитах Git, являются только для чтения и Git -только как это, Git было бы совершенно бесполезным, если бы у него не было способа извлечь этих файлов из коммита в другое место, где вы можете работать и с ними. Эта рабочая область, где Git извлекает файлы в пригодную для использования форму - обычные файлы, которые может использовать остальная часть вашего компьютера, - это ваше рабочее дерево или рабочее дерево .
Следовательно, после выбора определенного коммита, есть два набора файлов: замороженные в коммите и редактируемые в вашем рабочем дереве. Вы не можете видеть или делать что-либо с замороженными. Все, что вы можете сделать, это использовать копии рабочего дерева, но это все, что вам нужно.
Git может остановиться здесь. Mercurial, еще одна распределенная система управления версиями (DVCS), например Git, , останавливается на . С Mercurial вы извлекаете коммит в ваше рабочее дерево, затем вносите изменения, а затем фиксируете. Mercurial создает новый коммит из всего, что есть в вашем рабочем дереве. Но Git этого не делает. Вместо этого Git вставляет третью копию каждого файла, между замороженной, Git -только копией в коммите и используемой копией в вашем рабочем дереве. 1
Эти дополнительные копии каждого файла, которые находятся в замороженном формате - но на самом деле не заморожены - представляют собой большую часть индекса. Git также называет этот индекс промежуточной областью , поскольку Git использует индекс. Копии в замороженном формате каждого файла в индексе будут тем, что входит в следующий коммит, который вы делаете.
Когда вы запускаете git commit
, что делает Git это:
- сбор метаданных, таких как ваше имя и адрес электронной почты, а также сообщение в журнале
- добавление соответствующих материалов, таких как текущая дата и время, и идентификатор ha sh для текущий коммит в качестве родителя нового коммита
- заморозит все файлы в индексе
и запишет это как новый коммит. Он даже не смотрит на ваше рабочее дерево: вместо этого он строит новый коммит из того, что есть в index . 2
In другими словами, простой способ описать индекс состоит в том, что он содержит файлов, которые вы предлагаете поместить в следующий сделанный вами коммит . 3 Индекс изначально заполняется из коммита что вы выбрали с git checkout
или Git 2.23 или более поздней git switch
. Ваше рабочее дерево, которое иначе используется для вашего , также заполняется из этих файлов. Затем вы можете вносить любые изменения в свое рабочее дерево. Копии в индексе еще не изменены!
Когда вы запускаете git add
для файла рабочего дерева, Git копирует копию рабочего дерева в индекс , сжимая его в специальный Git -только формат в процессе. Этот файл перезаписывает все, что было в индексе под этим именем.
Если файл является совершенно новым для хранилища, т. Е. Никогда не был замечен ранее, он еще не будет в индексе . Если файл находится в каком-то коммите в репозитории, но не в коммите, который вы выбрали с git checkout
, файл также не будет в индексе. В этом случае git add
записывает файл в индекс, и теперь он находится в индексе. Таким образом, индекс может содержать файлы, которые не вообще не выходят из коммита, или он может содержать обновленные копии файлов, которые * выходят из коммита.
Вы также можете удалить файл из индекса. Запуск git rm <em>path</em>
удаляет как индексную копию именованного файла , так и копию рабочего дерева. Теперь, когда файл отсутствует в индексе, его нет в предлагаемом следующем коммите. Если вы делаете коммит сейчас, он не будет быть в коммите.
Когда вы запускаете git status
, Git начинается со сравнения текущего коммита с содержимым его индекса. Для каждого файла, который здесь тот же , Git ничего не говорит. Для каждого файла, который отличается , Git говорит, что этот файл подготовлен для фиксации . Файл, который пропал без вести - который находится в текущем коммите, но не в индексе - готовится к удалению, а файл, новый в индексе, помещается в новый файл.
Git затем, однако, выполняется сравнение second . На этот раз он сравнивает файлы в индексе с файлами в вашем рабочем дереве. Опять же, каждый файл может либо совпадать, либо отличаться, либо отсутствовать, либо в вашем рабочем дереве могут быть файлы, которых вообще нет в вашем индексе. Для файла, который соответствует, Git вообще ничего не говорит. Для файла, который не соответствует, Git говорит, что не подготовлен для фиксации . Для файла, который отсутствует в вашем рабочем дереве, Git говорит, что удаление не подготовлено для фиксации. Особенность здесь в том, что если файл новый , Git не говорит "новый", он говорит вместо этого без отслеживания .
Примечание. : Git копии файлов в индексе Git просто имеют длинные имена - например, path/to/file.ext
- это просто имя файла, а не папка path
, содержащая подпапку с именем to
, содержащая файл с именем file.ext
. Вот почему вы не можете хранить пустой каталог в Git: Git вообще не хранит каталоги, так как нет индексной записи типа "directory", а Git создает новые коммиты из того, что находится в его индексе , Если бы вы могли вставить пустой каталог в индекс, Git мог бы хранить пустой каталог. Но вы можете получить в индекс только файлы, символические c ссылки и gitlinks (информация о субмодуле). 4 Всякий раз, когда Git отправляется для извлечения коммита, содержащего file с именем path/to/file.ext
, Git знает, как создать необходимые каталоги / папки path
и path/to
, если необходимо.
1 Технически индекс содержит ссылки на Git объекты BLOB-объектов , а не на фактические копии данных файла. Однако если вы не начнете использовать команды низкого уровня git ls-files --stage
и git update-index
, вам не нужно заботиться об этом различии. Достаточно думать, что индекс содержит третью копию каждого файла.
2 Если вы используете git commit -a
, Git, по сути, сначала запустит git add -u
, до совершения. Здесь есть ряд скрытых проблем, о которых я не буду рассказывать, но при этом автоматически добавляются только те файлы, которые уже включены в индекс . Таким образом, только почти позволяет вам не заботиться об индексе: он падает в нескольких местах, включая случай совершенно нового файла.
3 Это несколько упрощенно. Индекс имеет дополнительные функции. Самая большая из них - та, с которой вы в конечном итоге столкнетесь и о которой нужно будет знать, - это то, что индекс играет расширенную роль во время конфликтующего слияния. Здесь мы не будем вдаваться в подробности.
4 Кто-то заметил, что это предоставляет хитрый способ Git хранить пустой каталог. Поскольку подмодуль сам по себе является каталогом, вы просто сохраняете в качестве подмодуля ссылку на полностью пустой дополнительный репозиторий. Без коммитов в этом хранилище ничто не может быть извлечено в этот подкаталог. Это дает вам пустой каталог. Это работает , но выглядит немного странно.
Игнорирование - то есть не жалоба и не добавление - файлы автоматически
Git часто используется сохранить исходные файлы для скомпилированных (или байтово скомпилированных, как в Python) языков. Эти компиляторы, как правило, записывают множество файлов, которые вы не хотите хранить с контролем версий. Удобно иметь возможность сказать: игнорировать все *.o
файлы , например, или игнорировать все файлы, найденные в __pycache__
каталогах .
Git Файлы .gitignore
являются механизмом для этого. Их формат немного сложен, потому что операционные системы обычно хранят файлы в виде записей в каталогах , или , папках , и Git должен вместить эти ОС. Итак:
- Имя без специальных символов означает игнорировать любой файл с этим именем, даже если он появляется в каком-либо подкаталоге .
- Имя с ведущим sla sh, как в
/program-x
, означает игнорировать файл с этим именем в этом каталоге, но не в подкаталогах . - Имя со встроенным sla sh, как в
sub/program-x
, означает игнорировать файл с именем sub/program-x
, как видно из этого каталога . Это не будет игнорировать other/program-x
и игнорировать sub/sub/program-x
: здесь учитывается только sub/program-x
. - Имя формы
sub/
означает игнорировать каталог (папка aka) с этим именем, но не файл с этим именем . Это означает, что файлы в a/sub/
также игнорируются, но файл с именем b/sub
не игнорируется. (Само это правило немного странно, но очень полезно для приведенных ниже правил отрицания.) Добавление ведущего sla sh «привязывает» имя к этому каталогу. - Last, начиная запись с
!
говорит Git не игнорировать это в конце концов. Это особенно полезно с этими шаблонами каталогов.
Кроме того, вы можете добавить символ шаблона глобуса *
, чтобы он соответствовал любому файлу, например, или другим символам стиля оболочки-глобуса, как перечислены в документации gitignore .
Предположим, например, что вы хотите, чтобы Git не жаловался на неотслеживаемые файлы где-либо внутри vendor/
, за исключением для любой файл, который вы положили в vendor/patches/
. Для этого вы должны убедиться, что Git сканирует каталог с именем vendor
для файлов и подкаталогов, что вы делаете, написав:
vendor/*
!vendor/patches/
Первая строка игнорирует все вещи - каталоги и файлы - внутри vendor
, но все равно сканирует vendor
сам. Вторая строка говорит, что когда Git встречается с vendor/patches
и это каталог, делает сканирует его и не игнорирует его файлы. Более поздняя строка !
переопределяет более раннюю строку *
. Следовательно, каталог с именем vendor/a/
и файл с именем vendor/description
оба игнорируются, но vendor/patches/
ищется для файлов, на которые можно пожаловаться, что они не отслеживаются.
En-masse add
операции
Когда вы запускаете git add
, вы можете дать ему отдельные имена файлов: например,
git add main.py
git add README.md
. Но вы также можете выполнять массовые операции «добавить все»:
git add .
или:
git add *
Они немного отличаются, когда ваша оболочка выполняет расширение *
, так как git add *
не вызовет git add
для файла с именем, например, .pylintrc
, но git add .
будет см. .pylintrc
и попытается добавить его.
Эти массовые операции добавляют каждый файл, который Git может найти таким образом, за исключением , что если файл в настоящий момент не отслежен - находится в вашем рабочем дереве, но не в индексе - это git add
будет пропускать файла, а не добавлять его.
Отсюда и название .gitignore
немного al ie
Лучшее имя для этого файла будет .git-do-not-complain-about-untracked-files-and-do-not-auto-add-these-files-when-using-an-en-masse-add-operation
. Но представьте, что вы пытаетесь создать это имя файла в новом хранилище.
Здесь есть еще одна тонкая особенность / ошибка: перечисление файла или шаблона в .gitignore
дает Git разрешение на clobber файл в некоторых угловых случаях. Они появляются не очень часто, но когда они появляются, они могут раздражать. Было бы неплохо, если бы вы могли пометить определенные файлы как игнорируемыми, но ценными: никогда не перезаписывайте и не удаляйте этот файл . Подробнее см. В этой довольно длинной почтовой ветке.
Файлы Gitignore могут появляться в подкаталогах
Довольно часто встречается один файл .gitignore
верхнего уровня, содержащий имена скомпилированные двоичные файлы и объектные файлы (*.o
, *.a
, *.so
, et c.). Но вы также можете разрешить подкаталогу специально игнорировать некоторые файлы. Например, предположим, у вас есть большой проект с библиотекой и куча разных программ, которые используют библиотеку. Каждая скомпилированная программа может быть подкаталогом репозитория верхнего уровня, причем библиотека также является подкаталогом. В каталоге каждой программы имеет смысл создать .gitignore
на этом уровне, который игнорирует исполняемый образ скомпилированной программы. Таким образом, верхний уровень .gitignore
перечисляет только те вещи, которые являются общими для всех подкаталогов. Файл lib/.gitignore
может содержать шаблон *.a
, поскольку в каталогах программ нет встроенных архивов. Каталог документации может содержать список созданных программой (не созданных человеком) файлов перекрестных ссылок или других сгенерированных файлов, которые не отображаются в каталогах, не относящихся к документации, и т. Д.
empty .gitignore
файл разрешен: он ничего не добавляет к набору вещей, которые следует игнорировать, но может занимать пустой каталог. Вы можете добавить этот файл .gitignore
к набору файлов в индексе Git, чтобы Git создавал каталог позже, при проверке этого коммита.