Принятый ответ не «заставляет Git » забывать « о файле ...» (исторически). Это только заставляет git игнорировать файл в настоящем / будущем.
Этот метод позволяет мерзавец полностью забыть игнорируемые файлы ( прошлое / настоящее / будущее), но не удаляет ничего из рабочего каталога (даже при повторном извлечении из удаленного).
Этот метод требует использования /.git/info/exclude
(предпочтительнее) или уже существующий .gitignore
в всех коммитах , которые имеют файлы , которые будут игнорироваться / забыто. 1
Все методы принудительного применения git игнорируют поведение за фактом, фактически переписывают историю и, следовательно, имеют значительные последствия для любых публичных / общих / совместных репозиториев, которые могут быть получены после этого процесса. 2
Общий совет: начните с чистого репо - все зафиксировано, ничего не ожидает в рабочем каталоге или индексе, и сделайте резервную копию !
Кроме того, комментарии / история изменений этого ответа ( и история изменений этого вопроса ) могут быть полезными / поучительными.
#commit up-to-date .gitignore (if not already existing)
#this command must be run on each branch
git add .gitignore
git commit -m "Create .gitignore"
#apply standard git ignore behavior only to current index, not working directory (--cached)
#if this command returns nothing, ensure /.git/info/exclude AND/OR .gitignore exist
#this command must be run on each branch
git ls-files -z --ignored --exclude-standard | xargs -0 git rm --cached
#Commit to prevent working directory data loss!
#this commit will be automatically deleted by the --prune-empty flag in the following command
#this command must be run on each branch
git commit -m "ignored index"
#Apply standard git ignore behavior RETROACTIVELY to all commits from all branches (--all)
#This step WILL delete ignored files from working directory UNLESS they have been dereferenced from the index by the commit above
#This step will also delete any "empty" commits. If deliberate "empty" commits should be kept, remove --prune-empty and instead run git reset HEAD^ immediately after this command
git filter-branch --tree-filter 'git ls-files -z --ignored --exclude-standard | xargs -0 git rm -f --ignore-unmatch' --prune-empty --tag-name-filter cat -- --all
#List all still-existing files that are now ignored properly
#if this command returns nothing, it's time to restore from backup and start over
#this command must be run on each branch
git ls-files --other --ignored --exclude-standard
Наконец, следуйте остальной части этого руководства GitHub (начиная с шага 6), которое включает важные предупреждения / информацию о командах ниже .
git push origin --force --all
git push origin --force --tags
git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now
Другие разработчики, которые извлекают данные из модифицированного удаленного репо, должны сделать резервную копию, а затем:
#fetch modified remote
git fetch --all
#"Pull" changes WITHOUT deleting newly-ignored files from working directory
#This will overwrite local tracked files with remote - ensure any local modifications are backed-up/stashed
git reset FETCH_HEAD
Сноски
1 Поскольку это /.git/info/exclude
может быть применено ко всем историческим коммитам с использованием приведенных выше инструкций, возможно, подробности о том, как .gitignore
вставить файл в исторический коммит (ы), в которых он необходим, выходят за рамки этого ответа. Я хотел, чтобы собственное место .gitignore
было в корневом коммите, как будто это было первое, что я сделал. Другим это может не волновать, поскольку они /.git/info/exclude
могут выполнить одно и то же независимо от того, где они .gitignore
существуют в истории коммитов, и, очевидно, переписывание истории является очень деликатным вопросом, даже когда известно о последствиях .
FWIW, потенциальные методы могут включать git rebase
или git filter-branch
копировать внешнее .gitignore
в каждый коммит, как ответы на этот вопрос
2 Применение принудительного игнорирования поведения git после фиксации результатов автономной git rm --cached
команды может привести к удалению недавно игнорируемого файла при будущих извлечениях из пульта с принудительным нажатием. --prune-empty
Флаг в следующей git filter-branch
команде позволяет избежать этой проблемы путем автоматического удаления предыдущего «удалить все игнорируемые файлы» индекс только совершить. Переписывание истории git также меняет хэши коммитов, что приведет к хаосу в будущих извлечениях из публичных / общих / совместных репозиториев. Пожалуйста, поймите все последствия, прежде чем делать это в таком репо. В этом руководстве GitHub указано следующее:
Скажите вашим соавторам перебазировать , а не объединить любые ветки, созданные ими из вашей старой (испорченной) истории хранилища. Один коммит слияния может заново ввести часть или всю испорченную историю, которую вы только что очистили.
Альтернативными решениями, не влияющими на удаленное репо, являются git update-index --assume-unchanged </path/file>
или git update-index --skip-worktree <file>
, примеры которых можно найти здесь .
git clean -X
звучит похоже, но это не относится к этой ситуации (когда файлы все еще отслеживаются Git). Я пишу это для тех, кто ищет решение не следовать по неверному маршруту.