Удалить папку и ее содержимое из истории Git/GitHub

Я работал над репозиторием в моей учетной записи GitHub, и с этой проблемой я столкнулся.

  • Проект Node.js с папкой с несколькими установленными пакетами npm
  • Пакеты были в node_modules папка
  • Добавил эту папку в репозиторий git и отправил код в github (в то время не думал о части npm)
  • Понял, что вам не нужно, чтобы эта папка была частью кода
  • Удалил эту папку, нажал на нее

В тот момент размер общего репозитория git составлял около 6 МБ, тогда как фактический код (все, кроме этой папки) составлял всего около 300 КБ.

Теперь, в конце концов, я ищу способ избавиться от деталей папки этого пакета из истории git, поэтому, если кто-то клонирует его, ему не нужно загружать историю в 6 МБ, где будут получены только реальные файлы. по состоянию на последний коммит будет 300KB.

Я искал возможные решения для этого и попробовал эти 2 метода

Казалось, что 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
Другие вопросы по тегам