Ответ 1
После импорта репозитория Subversion с многолетней историей я столкнулся с аналогичной проблемой с раздуванием из множества двоичных активов. В git: сокращение импорта Subversion, я описываю обрезку моего репозитория git с 4.5 GiB до 100 MiB.
Предполагая, что вы хотите удалить из всех файлов, удаленных в "Удалить медиафайлы" (6fe87d), вы можете адаптировать подход из моего сообщения в блоге к вашему репо
$ git filter-branch -d /dev/shm/git --index-filter \ "git rm --cached -f --ignore-unmatch media/Optika.1.3.?.*; \ git rm --cached -f --ignore-unmatch media/lens.svg; \ git rm --cached -f --ignore-unmatch media/lens_simulation.swf; \ git rm --cached -f --ignore-unmatch media/v.html" \ --tag-name-filter cat --prune-empty -- --all
В вашем реестре github нет тегов, но я включаю фильтр тегов-имен, если у вас есть личные теги.
Документация git filter-branch
охватывает параметр --prune-empty
.
--prune-empty
Некоторые виды фильтров генерируют пустые коммиты, которые оставляют дерево нетронутым. Этот переключатель позволяетgit-filter-branch
игнорировать такие коммиты...
Использование этой опции означает, что ваша перезаписанная история не будет содержать команду "Удалить медиафайлы", поскольку она больше не влияет на дерево. Медиа файлы никогда не создаются в новой истории.
В этот момент вы увидите дублирование в своем репозитории из-за другого документированного поведения.
Оригинальные ссылки, если они отличаются от перезаписанных, будут сохранены в пространстве имен
refs/original/
.
Если вы довольны недавно переписанной историей, удалите резервные копии.
$ git for-each-ref --format="%(refname)" refs/original/ | \ xargs -n 1 git update-ref -d
Git проявляет бдительность в отношении защиты вашей работы, поэтому даже после того, как все это намеренное переписывание и удаление reflog сохранят старые фиксации. Очистите их последовательностью из двух команд:
$ git reflog expire --verbose --expire=0 --all $ git gc --prune=0
Теперь ваш локальный репозиторий готов, но вам нужно нажать обновления GitHub. Вы могли бы делать их по одному. Для локальной ветки, скажем, мастера, вы запустите
$ git push -f origin master
Скажите, что у вас больше нет локальной ветки issue5. У вашего клона все еще есть ссылка ref origin/issue5, которая отслеживает, где она находится в вашем репозитории GitHub. Запуск git filter-branch
также изменяет все исходные ссылки, поэтому вы можете обновить GitHub без ветки.
$ git push -f origin origin/issue5:issue5
Если все ваши локальные ветки соответствуют их соответствующим коммитам на стороне GitHub (т.е. не разгруженные коммиты), вы можете выполнить массовое обновление.
$ git for-each-ref --format="%(refname)" refs/remotes/origin/ | \ grep -v 'HEAD$' | perl -pe 's,^refs/remotes/origin/,,' | \ xargs -n 1 -I '{}' git push -f origin 'refs/remotes/origin/{}:{}'
Вывод первого этапа - это список имен:
$ git for-each-ref --format="%(refname)" refs/remotes/origin/ refs/remotes/origin/HEAD refs/remotes/origin/issue2 refs/remotes/origin/issue3 refs/remotes/origin/issue5 refs/remotes/origin/master refs/remotes/origin/section_merge refs/remotes/origin/side-media-icons refs/remotes/origin/side-pane-splitter refs/remotes/origin/side-popup refs/remotes/origin/v2
Мы не хотим псевдо-ref HEAD и удаляем его с помощью grep -v
. В остальном мы используем Perl для удаления префикса refs/remotes/origin/
и для каждого запускаем команду формы
$ git push -f origin refs/remotes/origin/BRANCH:BRANCH