Удалить папку и ее содержимое из истории Git/GitHub
Я работал над репозиторием в моей учетной записи GitHub, и с этой проблемой я столкнулся.
- Проект Node.js с папкой с несколькими установленными пакетами npm
- Пакеты были в
node_modules
папка - Добавил эту папку в репозиторий git и отправил код в github (в то время не думал о части npm)
- Понял, что вам не нужно, чтобы эта папка была частью кода
- Удалил эту папку, нажал на нее
В тот момент размер общего репозитория git составлял около 6 МБ, тогда как фактический код (все, кроме этой папки) составлял всего около 300 КБ.
Теперь, в конце концов, я ищу способ избавиться от деталей папки этого пакета из истории git, поэтому, если кто-то клонирует его, ему не нужно загружать историю в 6 МБ, где будут получены только реальные файлы. по состоянию на последний коммит будет 300KB.
Я искал возможные решения для этого и попробовал эти 2 метода
- Удалить файл из репозитория git (история)
- http://help.github.com/remove-sensitive-data/
- https://gist.github.com/1588371
Казалось, что Gist сработал, когда после запуска скрипта он показал, что избавился от этой папки, и после этого показал, что было изменено 50 различных коммитов. Но это не позволило мне нажать этот код. Когда я попытался подтолкнуть его, он сказал Branch up to date
но показал 50 коммитов были изменены на git status
, Другие 2 метода тоже не помогли.
Теперь, несмотря на то, что он показал, что он избавился от истории этой папки, когда я проверил размер этого репо на моем локальном хосте, он все еще был около 6 МБ. (Я также удалил refs/original
папку, но не увидел изменения в размере репо).
Я хочу уточнить, есть ли способ избавиться не только от истории коммитов (что, как мне кажется, единственное, что произошло), но и от тех файлов, которые git продолжает предполагать, что кто-то хочет откатиться.
Допустим, решение для этого представлено и применяется на моем локальном хосте, но не может быть воспроизведено в этом репозитории GitHub, возможно ли клонировать это репо, выполнить откат к первому коммиту и выполнить его (или это означает, что git будет все еще есть история всех этих коммитов? - ака. 6MB).
Моя конечная цель здесь - найти лучший способ избавиться от содержимого папки из git, чтобы пользователю не приходилось загружать вещи размером 6 МБ и, возможно, иметь другие коммиты, которые никогда не касались папки модулей (это довольно много всего) в истории Git.
Как я могу это сделать?
9 ответов
Если вы здесь, чтобы скопировать и вставить код:
Это пример, который удаляет node_modules
из истории
git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
echo node_modules/ >> .gitignore
git add .gitignore
git commit -m 'Removing node_modules from git history'
git gc
git push origin master --force
Я считаю, что --tree-filter
опция, используемая в других ответах, может быть очень медленной, особенно в больших репозиториях с большим количеством коммитов.
Вот метод, который я использую, чтобы полностью удалить каталог из истории git, используя --index-filter
опция, которая работает намного быстрее:
# Make a fresh clone of YOUR_REPO
git clone YOUR_REPO
cd YOUR_REPO
# Create tracking branches of all branches
for remote in `git branch -r | grep -v /HEAD`; do git checkout --track $remote ; done
# Remove DIRECTORY_NAME from all commits, then remove the refs to the old commits
# (repeat these two commands for as many directories that you want to remove)
git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch DIRECTORY_NAME/' --prune-empty --tag-name-filter cat -- --all
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
# Ensure all old refs are fully removed
rm -Rf .git/logs .git/refs/original
# Perform a garbage collection to remove commits with no refs
git gc --prune=all --aggressive
# Force push all branches to overwrite their history
# (use with caution!)
git push origin --all --force
git push origin --tags --force
Вы можете проверить размер хранилища до и после gc
с:
git count-objects -vH
Похоже, что современный ответ на этот вопрос - не использоватьfilter-branch
напрямую (по крайней мере, сам git больше не рекомендует это) и отложить эту работу на внешний инструмент. В частности, в настоящее время рекомендуется использовать git-filter-repo. Автор этого инструмента приводит аргументы в пользу использованияfilter-branch
напрямую может привести к проблемам.
Большинство многострочных скриптов выше для удаления dir
из истории можно переписать как:
git filter-repo --path dir --invert-paths
Очевидно, этот инструмент более мощный, чем просто это. Вы можете применять фильтры по автору, электронной почте, ссылочному имени и другим параметрам (полная страница руководства здесь). Кроме того, это быстро. Установка проста - распространяется в самых разных форматах.
В дополнение к популярному ответу выше, я хотел бы добавить несколько заметок для Windows- систем. Команда
git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
работает отлично без каких-либо изменений! Поэтому вы не должны использовать
Remove-Item
,del
или что-нибудь еще вместоrm -rf
,Если вам нужно указать путь к файлу или каталогу, используйте косую черту, например
./path/to/node_modules
Лучший и самый точный метод, который я нашел, это загрузить файл bfg.jar: https://rtyley.github.io/bfg-repo-cleaner/
Затем запустите команды:
git clone --bare https://project/repository project-repository
cd project-repository
java -jar bfg.jar --delete-folders node_modules
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push --mirror https://project/new-repository
Если вы хотите удалить файлы, используйте вместо этого опцию delete-files:
java -jar bfg.jar --delete-files *.pyc
Для пользователей Windows, пожалуйста, обратите внимание на использование "
вместо '
Также добавлено -f
заставить команду, если другая резервная копия уже там.
git filter-branch -f --tree-filter "rm -rf FOLDERNAME" --prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
echo FOLDERNAME/ >> .gitignore
git add .gitignore
git commit -m "Removing FOLDERNAME from git history"
git gc
git push origin master --force
Завершите рецепт копирования и вставки, просто добавив команды в комментарии (для решения копирования и вставки) после их тестирования:
git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
echo node_modules/ >> .gitignore
git add .gitignore
git commit -m 'Removing node_modules from git history'
git gc
git push origin master --force
После этого вы можете удалить строку "node_modules/" из.gitignore
Я удалил папки bin и obj из старых проектов C#, используя git на windows. Будь осторожен с
git filter-branch --tree-filter "rm -rf bin" --prune-empty HEAD
Это разрушает целостность установки git, удаляя папку usr / bin в папке git install.
Для копипастеров ( отсюда ):
git filter-repo --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA
echo "YOUR-FILE-WITH-SENSITIVE-DATA" >> .gitignore
git add .gitignore
git commit -m "Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore"
git push origin --force --all