Хватит, чтобы git молча забивал игнорируемые файлы (ошибка в git?)?

Я нашел способ, которым git не будет просить вас спрятать, а вместо этого молча удалить ваши файлы, которые вы считали безопасными в.gitignore. Это верно даже в том случае, если у вас был тот же файл игнорирования со времени вашего первого коммита

Проблема возникает, когда вы находитесь в коммите, у которого указанный файл удален, но указан в.gitignore, а затем вы извлекаете другой коммит, где он существовал:

git init
mkdir ignored/
echo stuff > ignored/file
echo otherstuff > otherfile
git add -A
# Opps added my ignored folders files
# Forgeting to rm --cache
echo ignored/ > .gitignore ; git add .gitignore
git commit -m 'accidentally add ignored/file'
git status
touch dummyfile; git add dummyfile
# Remembered to rm --cache
git rm --cache -rf ignored/file #This file is now vulnerable to clobber
git commit -m 'add stuff'
echo somechange >> ignored/file

## Wait for it..
git checkout HEAD~
## somechange has been silently clobbered!!

# Please paste first paragraph, observe and then past the second.
# Note both commits have the correct ignore file and are not immune!

(перейдите в пустую папку перед вставкой кода выше в терминал)

Есть ли способ предотвратить этот тихий удар?

1 ответ

Это не ошибка (или, по крайней мере, разработчики git не считают это ошибкой).

Содержание .gitignore не являются "файлами, которые следует игнорировать" или "путями, которые не следует трогать"; вместо этого они являются "путями, которые не добавляются автоматически и не отображаются как неотслеживаемые" (что делает .gitignore плохое имя).

Когда вы зафиксировали файл или даже добавили его в индекс, он больше не игнорируется, независимо от того, указан ли он в списке. .gitignore,

Для некоторых файлов вы можете использовать git update-index --assume-unchanged или лучше) git update-index --skip-worktree, но в целом, если вы случайно зафиксировали файл, который у вас не должен быть, и вы хотите, чтобы он игнорировался, вы должны "переписать историю", чтобы полностью вынуть его из репозитория, чтобы получить хорошее поведение. Это не так уж сложно, если вы ничего не выдвинули и у вас мало коммитов, содержащих нежелательный файл, но гораздо сложнее, если вы нажали или у вас много таких коммитов.

Смотрите также Git - Разница между "предположим, без изменений" и "пропустить рабочее дерево".

[Текст ниже добавлен в декабре 2016 года]

Технические детали

Для Git существует краткое, простое и приятное определение отслеживаемого файла: файл отслеживается тогда и только тогда, когда для него есть запись в индексе.

"Предположим, что без изменений" и "пропустить рабочее дерево" - это флаги, которые вы можете установить или очистить вручную в индексе. Они являются отдельными флагами и могут быть установлены индивидуально, хотя не ясно, что означает установить оба. Намерение "предположить, что без изменений" состоит в том, чтобы просто сделать Git более быстрым, позволяя ему предположить, что файл не изменился и, следовательно, не требует обновления git addв то время как цель флага "пропустить рабочее дерево" состоит в том, чтобы сказать Git "руки прочь": не просто предполагайте, что оно не изменилось, постарайтесь сохранить его без изменений. Это сложнее, чем может показаться на первый взгляд; Подробнее об этом см. выше связанный пост.

Чтобы установить эти флаги, файл должен иметь индексную запись, поэтому он должен отслеживаться.

Если файл не отслеживается, он может или не может быть проигнорирован. Есть множество источников для них: не только на высшем уровне .gitignore, который содержит список (по одному на строку) варианта спецификации пути Git, который ограничен сопоставлением глобуса и отрицанием, но также .gitignore файлы в каждом подкаталоге в хранилище, файл $GIT_DIR/info/excludeесли он существует, и файл с именемcore.excludesFileесли эта запись конфигурации существует. Чтобы узнать, был ли файл проигнорирован и почему, используйтеgit check-ignore, доступно с версии Git 1.8.2. -v Опция говорит вам, какой файл управления пометил файл как проигнорированный.

К сожалению, как и в вопросе, на который это ответ, "игнорируется" имеет два значения. Несмотря на то, что сопоставление пути игнорирования держит Git в тайне от отслеживания файла, оно также дает Git возможность свободно взламывать файл.

Другие вопросы по тегам