Понимание маскировки.gitignore и git clean

Мне действительно трудно понять, как работает файл.gitignore...

Вот как выглядит мой файл:

custom/history
cache
*.log
custom/modules/*/Ext
upload
sugar-cron*
custom/application/Ext
custom/Extenstion/modules/*/Ext/Language
!custom/modules/*/Language/cs_CZ.*
!custom/modules/*/Language/en_us.*
custom/Extenstion/application/Ext/Language
!custom/Extenstion/application/Ext/Language/cs_CZ.*
!custom/Extenstion/application/Ext/Language/en_US.*
.htaccess
config.php
config_override.php
files.md5

Вот как выглядел мой git-статус:

apache@cb772759c68a sugarcrm$ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#    LOG.txt
#    deploy_backup/
nothing added to commit but untracked files present (use "git add" to track)

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

apache@cb772759c68a sugarcrm$ git clean -fd
Removing Disabled/upload:/
Removing LOG.txt
Removing custom/Extension/modules/Bugs/Ext/Language/
Removing custom/Extension/modules/Cases/Ext/Language/
Removing custom/Extension/modules/EmailAddresses/
Removing custom/Extension/modules/EmailParticipants/
Removing custom/Extension/modules/ForecastManagerWorksheets/
Removing custom/Extension/modules/ForecastWorksheets/
Removing custom/Extension/modules/Forecasts/
Removing custom/Extension/modules/Meetings/Ext/Layoutdefs/
Removing custom/Extension/modules/Meetings/Ext/WirelessLayoutdefs/
Removing custom/Extension/modules/Meetings/Ext/clients/
Removing custom/Extension/modules/ModuleBuilder/
Removing custom/Extension/modules/OutboundEmail/
Removing custom/Extension/modules/PdfManager/
Removing custom/Extension/modules/ProjectTask/Ext/Language/
Removing custom/Extension/modules/Quotas/
Removing custom/Extension/modules/Quotes/Ext/Dependencies/
Removing custom/Extension/modules/Targets/
Removing custom/Extension/modules/Tasks/Ext/Language/
Removing custom/Extension/modules/TimePeriods/
Removing custom/application/
Removing custom/install/
Removing custom/modules/Administration/
Removing custom/modules/Bugs/
Removing custom/modules/Cases/
Removing custom/modules/Contracts/
Removing custom/modules/Emails/
Removing custom/modules/HHP_Products/
Removing custom/modules/KBContents/
Removing custom/modules/Project/
Removing custom/modules/ProjectTask/
Removing custom/modules/ProspectLists/
Removing custom/modules/Prospects/
Removing custom/modules/Quotas/
Removing custom/modules/Reports/
Removing custom/modules/RevenueLineItems/
Removing custom/modules/Schedulers/
Removing custom/modules/Tags/
Removing custom/modules/Teams/
Removing custom/modules/hhp_assignment_zip/
Removing custom/modules/hhp_zipcode/
Removing custom/working/modules/Calls/
Removing custom/working/modules/Leads/clients/
Removing deploy_backup/
Removing deploy_log/
Removing dist/identity-provider/tests/docker/saml-test/config/simplesamlphp/config/
Removing vendor/sugarcrm/identity-provider/tests/docker/saml-test/config/simplesamlphp/config/

Первый пункт - удаленные файлы не были показаны после git status так очевидно, что они были частью "маски" gitignore... Кто-нибудь может объяснить, как любой из этих файлов соответствует любому шаблону в gitignore? подобно vendor/sugarcrm/identity-provider/tests/docker/saml-test/config/simplesamlphp/config/... Может кто-нибудь помочь мне с созданием пропитера gitignore?

Второй момент - я думал, что.gitignore "защищает" эти неверсированные файлы от git cleanтот мерзавец буквально не предпринимает никаких действий на них. Поэтому очевидно, что он действительно удаляет их... как я не могу удалить неверсированные файлы при использовании git clean?

РЕДАКТИРОВАТЬ: я перепутал git clean с git rm, я все время говорил о git clean

РЕДАКТИРОВАТЬ 2: оказалось, что удаленные каталоги, которые не соответствуют.gitignore, были "пустыми" в конце концов. (у них были подкаталоги, но дерево каталогов было без каких-либо файлов...)

2 ответа

Решение

TL;DR

Вы неправильно поняли, что git clean удаляет по умолчанию и с -d, (Примечание: я не большой поклонник git clean себя; слишком легко удалить драгоценные файлы.)

Долго

Как отмечает Phd, перечисление файла в .gitignore специально отключает, по умолчанию, имея git clean убери это прочь Тем не мение, git clean (значительно) сложнее, чем это. Мы немного углубимся в это.

Во-первых, давайте рассмотрим одну особенность .gitignore записей. Если вы уже знаете все это (но никто не знает:-)), вы можете перейти к git clean конкретные разделы ниже.

  1. Отслеживаемый файл (который сейчас находится в индексе) никогда не игнорируется, поэтому соответствие .gitignore или эквивалент (например, .git/info/exclude) картина не имеет значения.

    Фраза в индексе прямо сейчас означает именно это. Когда вы используете git add или же git rm --cached добавить или удалить файл, который изменяет его отслеживаемость. Вы также можете использовать git ls-files --stage выгрузить полный список каждого файла в индексе вместе с его промежуточными данными - mode, hash и stage-slot-number - или без --stage чтобы получить только имена.

  2. Файл (не каталог), который был найден Git и которого нет в индексе, не отслеживается. Git не хранит каталоги, поэтому каталоги никогда не появляются в индексе. 1 Отслеживаемый или неотслеживаемый является чисто свойством файлов.

  3. Не отслеживаемый файл также может быть проигнорированным файлом. Если так, git add не добавит его, даже если вы укажете его явно в командной строке (хотя вы можете указать его явно и использовать --force добавить это).

    Это означает, что файлы (но не каталоги) попадают в одну из трех категорий: отслеживаемые, неотслеживаемые (только) или неотслеживаемые и игнорируемые. Это важно для git status, который жалуется только на неотслеживаемые файлы (не отслеживаемые и игнорируемые), но и в момент для git clean также.

  4. Наконец, когда Git выполняет полный поиск / сканирование дерева каталогов - как в git add . например - и обнаруживает каталог, который он может пропустить (не имеет отслеживаемых файлов внутри него), Git проверит, соответствует ли сам каталог .gitignore шаблон, и если так, не заглядывайте внутрь. Это ускоряет git status а также git add -A / git add . в таких каталогах (иногда очень много, если вы можете игнорировать, например, целое дерево поставщиков или SDK).

Правило 4: почему, если вы хотите не игнорировать определенные пути к файлам, которые находятся под каким-либо путем к каталогу, вы должны указать Git специально не игнорировать каталог. Если вы игнорируете каталог, Git может никогда не заглянуть внутрь каталога. Это влияет на эти три строки, в частности:

custom/Extenstion/application/Ext/Language
!custom/Extenstion/application/Ext/Language/cs_CZ.*
!custom/Extenstion/application/Ext/Language/en_US.*

Если вы проигнорировали весь каталог custom/Extenstion/application/Ext/Language, Git не заглядывает внутрь и никогда не найдет подходящих файлов custom/Extenstion/application/Ext/Language/cs_CZ.* игнорировать это. Поэтому необходимо исключить сам каталог из игнорируемого статуса: вы должны изменить первую строку, чтобы читать custom/Extenstion/application/Ext/Language/*, так что Git должен заглянуть внутрь каталога. Последующие строки, заканчивающиеся на cs_CZ.* а также en_US.* переопределит игнорируемый статус для чешских и англо-американских файлов.


1 Фактически, они могут появляться в указателе, но только для того, чтобы их можно было рассматривать как особые случаи. git ls-files, который может показать вам содержимое индекса, пропускает прямо над ними.


С помощью git clean -d четко изменяет правило 4

Git может удалить каталог, только если он пуст. Это общее правило, поддерживаемое ОС: если каталог d содержит несколько файлов d/f1, d/f2 и так далее, и вы должны были удалить d без удаления файлов у вас возникнут проблемы с файлами. Система заставляет вас сначала удалить файлы в каталоге. Это относится и к подкаталогам: вы не можете удалить d если d/sub существует, даже если d/sub сам по себе пустой каталог. Только пустые каталоги могут быть удалены.

Бег git clean без -d не только оставляет правило 4 установленным, но фактически расширяет его. Например, в примере, с которого мы начали, Git замечает, что (1) custom/Extenstion/application/Ext/Language это каталог; (2) каталог соответствует шаблону игнорирования; так (3) при условии, что нет файлов в custom/Extenstion/application/Ext/Language которые уже отслежены, Git может и пропустит весь каталог (и, конечно, не удалит его, так как git clean работает без -d).

Предположим, что есть еще один каталог с именем xyzzy/ в списке нет файлов Этот каталог может быть полностью пустым. В этом случае в нем нет неотслеживаемых файлов по определению; так git clean без -d ничего не должен с этим делать. Или это могут быть файлы; эти файлы по определению не отслеживаются (и, следовательно, могут не отслеживаться и игнорироваться), но вы сказали не удалять каталоги, поэтому git clean до сих пор даже не удосужился заглянуть внутрь. Это немного странный случай: Git часто не заглядывает в неизвестные каталоги. 2 (Вы видите это с git status а также: вы должны использовать git status -uall чтобы найти файлы внутри таинственного каталога. Но git add -A или же git add . должен заглянуть внутрь, если каталог не игнорируется, поэтому правило 4 немного сложнее в общем случае.)

Бег с -dхотя, по-видимому, полностью исключает правило 4. Опять же, чтобы удалить каталог, Git должен сначала удалить все файлы в каталоге. Чтобы сделать это, Git также должен перечислить содержимое. Так что если вы скажете git clean использовать -d представляется целесообразным полностью отключить правило 4. Отсутствие каталога в имени пути заставит Git сканировать содержимое каталога. Либо нам уже нужно было заглянуть внутрь, потому что есть отслеживаемые файлы, либо нам нужно заглянуть внутрь, чтобы удалить файлы, чтобы удалить каталог.


2 Обратите внимание, что "неизвестный" - это не то же самое, что "неотслеживаемый". Это даже не термин Git; Я сделал это здесь. Однако, как мы увидим, было бы неплохо, если бы Git определил фразу "каталог без отслеживания".


Какие git clean удаляет

Бег git clean -n покажет вам, что он будет удалять. Этот показ использует некоторые сокращения: удаление каталога подразумевает удаление всех файлов в этом каталоге, включая (рекурсивно) подкаталоги с подфайлами. Это безопаснее, чем бегать с -f вместо -n, поскольку -f показывает то, что он удалил, таким же образом -n показывает, что это будет удалить.

По умолчанию, git clean удаляет файлы, которые не отслеживаются, но не файлы, которые не отслеживаются и игнорируются. То есть вернитесь к пункту 3 выше и посмотрите на три классификации файлов: git clean удаляет среднюю классификацию (только). Добавление -X (верхний регистр X) говорит Git: не удаляйте файлы без отслеживания; вместо этого удалите неотслеживаемые и игнорируемые файлы.

Добавление -x говорит Git: не читайте обычные файлы директив игнорирования, такие как .gitignore, На этом этапе никакие файлы не будут игнорироваться, поэтому (независимо от того, какие файлы отслеживаются) никакие файлы не могут быть отслежены и проигнорированы. Сочетая это с -X не имеет смысла, 3 так git clean запрещает вам использовать оба -x а также -X,

Бег git clean с -d добавляет удаление пустого каталога. Здесь все становится особенно блекло, хотя. Кажется, что классификация отслеживаемых, не отслеживаемых и не отслеживаемых и игнорируемых Git немного нарушается. В документации сказано, что -d будут:

Удалите неотслеживаемые каталоги в дополнение к неотслеживаемым файлам.

Но у Git нет определения неотслеживаемых каталогов. "Tracked-ness" является исключительно свойством файлов. В сноске мы увидели, что каталоги проникают в индекс как невидимые объекты (для ускорения различных операций Git), но это не означает, что каталоги отслеживаются.

Мы можем составить один: "неотслеживаемый каталог" может быть каталогом, который не содержит отслеживаемых файлов. Я думаю (но не доказал, к моему собственному удовлетворению), что это определение работает и объясняет git clean Поведение Тем не менее, было бы очень полезно, если бы документация Git действительно определила это правильно.


3 Объединение -x а также -X с -e может иметь практическое применение, но Git все еще запрещает это, по крайней мере, на сегодняшний день.

  1. .gitignore игнорирует файл от добавления и подтверждения. Это не защищает их от очистки, как раз наоборот.

  2. Эти очищенные файлы связаны с .gitignore следующим образом:

    custom / Расширение / модули / Ошибки /Ext/ Язык /Custom / Расширение / Модули / Случаи /Ext/ Язык /

матч custom/modules/*/Ext править.

LOG.txt
vendor/sugarcrm/identity-provider/tests/docker/saml-test/config/simplesamlphp/config/

Файлы не были добавлены в индекс, поэтому они могут быть очищены.

  1. Чтобы избежать очистки неверсированных файлов, не запускайте git clean, Удалите ненужные файлы вручную.
Другие вопросы по тегам