Удалить папку и ее содержимое из git/истории GitHub
Я работал над репозиторием на моей учетной записи GitHub, и это проблема, на которую я наткнулся.
- Node.js проект с папкой с несколькими установленными пакетами npm
- Пакеты находились в папке
node_modules
- Добавил эту папку в репозиторий git и нажал код на github (в то время не думал о части npm)
- Понял, что вам действительно не нужна эта папка, чтобы быть частью кода
- Удалил эту папку, нажал ее
В этом случае размер полного репозитория git был около 6 МБ, где фактический код (все, кроме этой папки) был всего около 300 КБ.
Теперь то, что я ищу в конце, - это способ избавиться от деталей этой папки пакета от истории git, поэтому, если кто-то ее клонирует, им не нужно загружать историю с размером в 6 Мб, где только фактическая файлы, которые они получат с последнего фиксации, будут 300 КБ.
Я искал возможные решения для этого и пробовал эти 2 метода
Кажется, что Gist работал, где после запуска script он показал, что он избавился от этой папки, и после этого он показал, что было изменено 50 разных коммитов. Но это не позволило мне нажать этот код. Когда я попытался нажать, он сказал Branch up to date
, но показал, что 50 коммитов были изменены на git status
. Другие 2 метода тоже не помогли.
Теперь, хотя он показал, что он избавился от этой истории папок, когда я проверил размер этого репо на моем локальном хосте, он все еще находился около 6 МБ. (Я также удалил папку refs/original
, но не видел изменения размера репо).
То, что я хочу уточнить, - это способ избавиться от не только истории фиксации (которая является единственной вещью, которая, как мне кажется, произошла), но и тех файлов git, которые предполагают, что нужно откатить.
Давайте скажем, что решение представлено для этого и применяется на моем локальном хосте, но не может быть воспроизведено в этом репо GitHub, можно ли клонировать это репо, откат к первому фиксатору выполнить трюк и нажать его (или это означает что git будет по-прежнему иметь историю всех этих коммитов? - aka. 6MB).
Моя конечная цель заключается в том, чтобы в основном найти лучший способ избавиться от содержимого папки из git, чтобы пользователь не загружал вещи на 6 МБ и, возможно, имел другие коммиты, которые никогда не касались (что почти все из них) в истории git.
Как я могу это сделать?
Ответы
Ответ 1
Если вы хотите скопировать и вставить код:
Это пример, который удаляет 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
Что на самом деле делает Git:
Первая строка перебирает все ссылки в том же дереве (--tree -f ilter), что и HEAD (ваша текущая ветвь), выполняя команду 'rm -rf node_modules'. Эта команда удаляет папку node_modules (-r, без -r, rm не будет удалять папки), без запроса пользователю (-f). Добавленный --prune-empty удаляет бесполезные (ничего не меняющие) фиксации рекурсивно.
Вторая строка удаляет ссылку на эту старую ветку.
Остальные команды относительно просты.
Ответ 2
Я нахожу, что параметр --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
Ответ 3
В дополнение к популярному ответу выше я хотел бы добавить несколько заметок для Windows -систем. Команда
git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
-
работает отлично без модификации! Поэтому вы не должны использовать Remove-Item
, del
или что-то еще вместо rm -rf
.
-
Если вам нужно указать путь к файлу или каталогу, используйте слэши, например ./path/to/node_modules
Ответ 4
Лучший и самый точный метод, который я нашел, это загрузить файл 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 DIRECTORY_NAME # i.e. 'node_modules' in other examples
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
Ответ 5
Завершить копию и вставить рецепт, просто добавив команды в комментарии (для решения для копирования-вставки), после тестирования:
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
Ответ 6
Для пользователя 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
Ответ 7
Я удалил папки bin и obj из старых проектов С#, используя git на windows. Будь осторожен с
git filter-branch --tree-filter "rm -rf bin" --prune-empty HEAD
Это разрушает целостность установки git, удаляя папку usr/bin в папке git install.
Ответ 8
На 2 верхних ответа вопрос: все строки можно легко понять, но ~~~ bash git for-each-ref --format = "% (refname)" refs/original/| xargs -n 1 git update-ref -d ~~~ не будет делать ничего для каждой моей версии git, поскольку git for-each-ref
ничего не перечисляет. Я протестировал и обнаружил: ~~~ bash git for-each-ref --format = "% (refname)" refs/remotes/origin/~~~ может перечислить все мои удаленные ссылки. @Mohsen или @lee -n etherton, пожалуйста, помогите по этому вопросу?