Существует файл, который отслеживается git
, но теперь файл находится в списке .gitignore
.
Тем не менее, этот файл продолжает отображаться в git status
после его редактирования. Как вы заставляете git
полностью забыть об этом?
Существует файл, который отслеживается git
, но теперь файл находится в списке .gitignore
.
Тем не менее, этот файл продолжает отображаться в git status
после его редактирования. Как вы заставляете git
полностью забыть об этом?
.gitignore
предотвратит добавление неотслеживаемых файлов (без add -f
) в набор файлов, отслеживаемых git, однако git продолжит отслеживать любые файлы, которые уже отслеживаются.
Чтобы остановить отслеживание файла, вам необходимо удалить его из индекса. Это может быть достигнуто с помощью этой команды.
git rm --cached <file>
Если вы хотите удалить всю папку, вам нужно рекурсивно удалить все файлы в ней.
git rm -r --cached <folder>
Удаление файла из заголовка ревизии произойдет при следующем коммите.
ВНИМАНИЕ: Хотя это не удалит физический файл из вашего локального, он будет удалять файлы с машин других разработчиков при следующем git pull
.
В приведенной ниже последовательности команд будут удалены все элементы из индекса Git (не из рабочего каталога или локального репо), а затем обновляется индекс Git, при этом игнорируется Git. PS. Index = Кэш
Во-первых:
git rm -r --cached .
git add .
Тогда:
git commit -am "Remove ignored files"
git update-index делает всю работу за меня:
git update-index --assume-unchanged <file>
Примечание. Это решение фактически не зависит от .gitignore
как gitignore предназначен только для неотслеживаемых файлов.
изменение: так как этот ответ был опубликован, новая опция была создана, и это должно быть предпочтительным. Вы должны использовать --skip-worktree
который предназначен для измененных отслеживаемых файлов, которые пользователь больше не хочет фиксировать, и сохраняет --assume-unchanged
для повышения производительности, чтобы git не проверял состояние больших отслеживаемых файлов. См. fooobar.com/questions/1817/... для получения дополнительной информации...
git update-index --skip-worktree <file>
git ls-files --ignored --exclude-standard -z | xargs -0 git rm --cached
git commit -am "Remove ignored files"
Это берет список игнорируемых файлов и удаляет их из индекса, а затем фиксирует изменения.
Я всегда использую эту команду для удаления этих невоспроизводимых файлов. Однострочный, Unix-стиль, чистый вывод:
git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm -r --cached
В нем перечислены все ваши проигнорированные файлы, вместо каждой строки вывода заменена линией с кавычками, чтобы обрабатывать пути с пробелами внутри и передавать все в git rm -r --cached
, чтобы удалить пути/файлы/директории из индекса.
переместите его, зафиксируйте, а затем верните его. Это сработало для меня в прошлом. Вероятно, есть способ "gittier" выполнить это.
Если вы не можете git rm
отслеживаемый файл, потому что это может понадобиться другим людям (предупреждение, даже если вы нажмете git rm --cached
, когда кто-то другой получит это изменение, его файлы будут удалены в их файловой системе). Это часто делается из-за переопределения файла конфигурации, учетных данных аутентификации и т.д. Пожалуйста, посмотрите на https://gist.github.com/1423106 способы, которыми люди обошли проблему.
Подвести итоги:
Ссылка источника: http://www.codeblocq.com/2016/01/Untrack-files-already-added-to-git-repository-based-on-gitignore/
Допустим, вы уже добавили/перенесли некоторые файлы в свой репозиторий git, а затем добавили их в свой.gitignore; эти файлы все равно будут присутствовать в вашем индексе репозитория. В этой статье мы увидим, как избавиться от них.
Прежде чем продолжить, убедитесь, что все ваши изменения зафиксированы, включая файл.gitignore.
Чтобы очистить свое репо, используйте:
git rm -r --cached .
Команда rm
может быть неумолимой. Если вы хотите попробовать, что он делает заранее, добавьте -n
или --dry-run
чтобы проверить все.
git add .
git commit -m ".gitignore fix"
Ваш репозиторий чист :)
Нажмите на изменения на пульте дистанционного управления, чтобы увидеть изменения, которые там также эффективны.
Я сделал это, используя git ветвь фильтра. Точная команда, которую я использовал, была взята с man-страницы:
ПРЕДУПРЕЖДЕНИЕ: это приведет к удалению файла из всей истории
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
Эта команда воссоздает всю историю фиксации, выполнив git rm
перед каждой фиксацией и таким образом избавится от указанного файла. Не забудьте выполнить резервное копирование перед запуском команды, поскольку она будет потеряна.
(В Linux) я хотел использовать сообщения, предлагающие подход ls-files --ignored --exclude-standard | xargs git rm -r --cached
. Однако (некоторые из) файлов, которые должны быть удалены, имели встроенные символы newline/LF/\n
в их именах. Ни одно из решений:
git ls-files --ignored --exclude-standard | xargs -d"\n" git rm --cached
git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm -r --cached
справиться с этой ситуацией (получить ошибки о файлах не найдено).
git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached
Это использует аргумент -z
для ls-files, а аргумент -0
- xargs, чтобы безопасно/корректно использовать для "неприятных" символов в именах файлов.
На странице руководства git -ls-files (1) указано:
Если параметр -z не используется, символы TAB, LF и обратная косая черта в pathnames представлены как \t,\n и\\соответственно.
поэтому я думаю, что мое решение необходимо, если в именах файлов есть какие-либо из этих символов.
EDIT: меня попросили добавить, что --- как и любая команда git rm
- за ней должен следовать commit, чтобы сделать удаление перманентным, например. git commit -am "Remove ignored files"
.
Обновите файл .gitignore
- например, добавьте папку, в которую вы не хотите отслеживать .gitignore
.
git rm -r --cached .
- удалить все отслеженные файлы, включая нежелательные и нежелательные. Ваш код будет безопасным, если вы сохранили его локально.
git add .
- все файлы будут добавлены обратно, кроме тех, что указаны в .gitignore
.
Совет шляпы @AkiraYamamoto для указания в правильном направлении.
Я думаю, что, возможно, git не может полностью забыть о файле из-за его концепции (раздел "Снимки, а не разницы" ).
Эта проблема отсутствует, например, при использовании CVS. CVS хранит информацию как список изменений на основе файлов. Информация для CVS представляет собой набор файлов и изменений, внесенных в каждый файл с течением времени.
Но в git каждый раз, когда вы совершаете фиксацию или сохраняете состояние своего проекта, в нем в основном делается фотография того, что все ваши файлы выглядят в данный момент и хранит ссылку на этот снимок, Итак, если вы добавили файл один раз, он всегда будет присутствовать в этом снимке.
Эти 2 статьи были полезны для меня:
git предположить-без изменений vs skip-worktree и Как игнорировать изменения в отслеживаемых файлах с помощью Git
Основываясь на этом, я делаю следующее, если файл уже отслеживается:
git update-index --skip-worktree <file>
С этого момента все локальные изменения в этом файле будут проигнорированы и не будут удалены. Если файл изменен на удаленном, конфликт будет иметь место, когда git pull
. Стой не будет работать. Чтобы решить проблему, скопируйте содержимое файла в безопасное место и выполните следующие действия:
git update-index --no-skip-worktree <file>
git stash
git pull
Содержимое файла будет заменено удаленным контентом. Вставьте свои изменения из безопасного места в файл и выполните снова:
git update-index --skip-worktree <file>
Если каждый, кто работает с проектом, выполнит git update-index --skip-worktree <file>
, проблемы с pull
должны отсутствовать. Это решение подходит для файлов конфигураций, когда каждый разработчик имеет собственную конфигурацию проекта.
Это не очень удобно делать каждый раз, когда файл был изменен на удаленном компьютере, но может защитить его от перезаписи удаленным контентом.
Делайте следующие шаги поочередно, у вас все будет хорошо.
1. удалить ошибочно добавленные файлы из каталога/хранилища. Вы можете использовать команду "rm -r" (для linux) или удалить их, просматривая каталоги. Или переместите их в другое место на вашем ПК. [Возможно, вам придется закрыть IDE, если вы хотите переместить/удалить ]
2. добавьте файлы/каталоги в файл gitignore
и сохраните его.
3. Теперь удалите их из кеша git с помощью этих команд (если существует более одного каталога, удалите их один за другим, повторно выполнив эту команду)
git rm -r --cached path-to-those-files
4. Теперь сделайте коммит и нажмите, используйте эти команды. Это удалит эти файлы из git remote и заставит git перестать отслеживать эти файлы.
git add .
git commit -m "removed unnecessary files from git"
git push origin
Ответ копирования/вставки: git rm --cached -r.; git add.; git status
git rm --cached -r.; git add.; git status
Эта команда будет игнорировать файлы, которые уже были переданы в репозиторий Git, но теперь мы добавили их в .gitignore
.
Ответ от Matt Fear был самым эффективным IMHO. Следующее - это просто PowerShell script для тех, кто в Windows только удаляет файлы из своего репозитория git, который соответствует их списку исключений.
# Get files matching exclusionsfrom .gitignore
# Excluding comments and empty lines
$ignoreFiles = gc .gitignore | ?{$_ -notmatch "#"} | ?{$_ -match "\S"} | % {
$ignore = "*" + $_ + "*"
(gci -r -i $ignore).FullName
}
$ignoreFiles = $ignoreFiles| ?{$_ -match "\S"}
# Remove each of these file from Git
$ignoreFiles | % { git rm $_}
git add .
Переместите или скопируйте файл в безопасное место, чтобы вы не потеряли его. Затем git rm файл и commit. Файл будет отображаться, если вы вернетесь к одному из этих ранее коммитов, или к другой ветке, где она не была удалена. Однако во всех будущих коммитах вы не увидите файл снова. Если файл находится в git игнорировать, вы можете переместить его обратно в папку, а git не увидит его.
BFG специально разработан для удаления нежелательных данных, таких как большие файлы или пароли из репозиториев Git, поэтому он имеет простой флаг, который удалит любые большие исторические файлы (не в вашем-текущем): "-strip-blobs-больше-чем"
$ java -jar bfg.jar --strip-blobs-bigger-than 100M
Если вы хотите указать файлы по имени, вы также можете это сделать:
$ java -jar bfg.jar --delete-files *.mp4
BFG на 10-1000x быстрее, чем Git фильтр-ветвь, и, как правило, гораздо проще в использовании - проверьте инструкции для полного использования и examples для более подробной информации.
Источник: https://confluence.atlassian.com/bitbucket/reduce-repository-size-321848262.html
Если вы не хотите использовать CLI и работаете с Windows, очень простое решение - использовать TortoiseGit, у него есть действие "Удалить (сохранить локальное)" в меню, которое работает нормально.
Мне понравился ответ JonBrave, но у меня довольно грязные рабочие каталоги, которые фиксируют -a, немного пугает меня, поэтому вот что я сделал:
git config --global alias.exclude-ignored '! git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached && git ls-files -z --ignored --exclude-standard | xargs -0 git stage && git stage.gitignore && git commit -m "новый gitignore и удалить проигнорированные файлы из индекса"
разрушение:
git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached
git ls-files -z --ignored --exclude-standard | xargs -0 git stage
git stage .gitignore
git commit -m "new gitignore and remove ignored files from index"
Использование команды git rm --cached
не отвечает на исходный вопрос:
Как вы заставляете
git
полностью забыть о [файле]?
Фактически, это решение приведет к удалению файла во всех остальных экземплярах хранилища при выполнении git pull
!
Правильный способ заставить git забыть о файле задокументирован здесь GitHub.
Я рекомендую прочитать документацию, но в основном:
git fetch --all
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch full/path/to/file' --prune-empty --tag-name-filter cat -- --all
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
просто замените full/path/to/file
на полный путь к файлу. Убедитесь, что вы добавили файл в свой .gitignore
.
Вам также нужно (временно) разрешить не-ускоренные пересылки в ваш репозиторий, так как вы изменяете свою историю git.
Это уже не проблема в последнем git (v2.17.1 на момент написания).
В .gitignore
игнорирует файлы с отслеживанием, но удаленные. Вы можете проверить это самостоятельно, выполнив следующий сценарий. Окончательное выражение о git status
должно сообщать "ничего не делать".
# Create empty repo
mkdir gitignore-test
cd gitignore-test
git init
# Create a file and commit it
echo "hello" > file
git add file
git commit -m initial
# Add the file to gitignore and commit
echo "file" > .gitignore
git add .gitignore
git commit -m gitignore
# Remove the file and commit
git rm file
git commit -m "removed file"
# Reintroduce the file and check status.
# .gitignore is now respected - status reports "nothing to commit".
echo "hello" > file
git status
В случае уже совершенного DS_Store
:
find . -name .DS_Store -print0 | xargs -0 git rm --ignore-unmatch
Игнорировать их:
echo ".DS_Store" >> ~/.gitignore_global
echo "._.DS_Store" >> ~/.gitignore_global
echo "**/.DS_Store" >> ~/.gitignore_global
echo "**/._.DS_Store" >> ~/.gitignore_global
git config --global core.excludesfile ~/.gitignore_global
Наконец, сделайте фиксацию!
Специально для файлов на основе IDE, я использую это:
Например, slnx.sqlite, я просто полностью избавился от него следующим образом:
git rm {PATH_OF_THE_FILE}/slnx.sqlite -f
git commit -m "remove slnx.sqlite"
Просто имейте в виду, что некоторые из этих файлов хранят некоторые локальные пользовательские настройки и предпочтения для проектов (например, какие файлы у вас были открыты). Таким образом, каждый раз, когда вы перемещаетесь или делаете какие-либо изменения в вашей IDE, этот файл изменяется, и поэтому он проверяет его и показывает, что есть незафиксированные изменения.
Принятый ответ не "заставляет Git " забывать " о файле..." (исторически). Это только заставляет git игнорировать файл в настоящем/будущем.
Этот метод заставляет git полностью забывать игнорируемые файлы (прошлое/настоящее/будущее), но не не удаляет что-либо из рабочего каталога (даже при повторном извлечении из удаленного).
Этот метод требует использования
/.git/info/exclude
(предпочтительно) ИЛИ ранее pre-existing.gitignore
во всех коммитах, в которых есть файлы, которые должны быть проигнорированы/забыты. 1Все методы принудительного применения git игнорируют поведение после факта, эффективно переписывают историю и, таким образом, имеют значительные последствия для любых публичных/общих/совлокальных репозиториев, которые могут быть извлечены после этого процесса. 2
Общий совет: начните с чистого репо - все зафиксировано, ничего не ожидает в рабочем каталоге или индексе, и сделайте резервную копию!
Also, the comments/revision history of this answer (and revision history of this question) may be useful/enlightening.
#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 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
существует в истории коммитов, и ясно, что переписывание истории является очень раздражающим предметом, даже когда известно о последствия.
Кстати, потенциальные методы могут включать в себя git rebase
или git filter-branch
, который копирует внешний .gitignore
в каждый коммит, как ответы на этот вопрос
2 Принудительное поведение git ignore после фиксации результатов автономной команды git rm --cached
может привести к тому, что delete вновь игнорируется файл в будущем при извлечении из пульта с принудительным нажатием. Флаг --prune-empty
в следующей команде git filter-branch
позволяет избежать этой проблемы, автоматически удаляя предыдущую фиксацию только для индекса "удалить все игнорируемые файлы". Переписывание истории git также меняет хэши коммитов, которые нанесут ущерб будущим извлечениям из публичных/общих/совлокальных репозиториев. Пожалуйста, полностью поймите последствия, прежде чем делать это с таким репо. В этом руководстве по GitHub указано следующее:
Скажите вашим соавторам перебазировать, а не объединять любые ветки, которые они создали из вашей старой (испорченной) истории репозитория. Одна фиксация слияния может восстановить некоторые или всю испорченную историю, которую вы только что очистили.
Альтернативными решениями, которые не влияют на удаленное репо, являются git update-index --assume-unchanged </path/file>
или git update-index --skip-worktree <file>
, примеры которых можно найти здесь.
На mac:
$ git --version
git version 2.6.4
$ uname -a
Darwin MUSRV186016-382 14.5.0 Darwin Kernel Version 14.5.0: Sun Sep 25 22:07:15 PDT 2016; root:xnu-2782.50.9~1/RELEASE_X86_64 x86_64
1. Удалите файлы DS_Store из списка файлов, отслеживаемых git в ветке foo:
$ for file in $(git ls-tree -r foo --name-only | grep -i DS_Store); do git rm --cached $file; done
2. Commit:
$ git commit -m "Removed .DS_Store files"
3. Проверьте, что файлы больше не отслеживаются
$ git ls-tree -r foo --name-only
# There should not be anything coming back
4. Нажмите, чтобы удалить их из пульта:
$ git push