После импорта репозитория Subversion с многолетней историей я столкнулся с похожей проблемой с раздуванием из-за большого количества бинарных ресурсов. В git: сокращение импорта Subversion , я описываю обрезку моего репозитория git с 4,5 ГиБ до примерно 100 МБ.
Предполагая, что вы хотите удалить из всех коммитов файлы, удаленные в «Удаление медиа-файлов» (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. Вы можете сделать их по одному за раз. Для локальной ветки, скажем master, вы запустите
$ git push -f origin master
Скажем, у вас больше нет локальной ветки Issue5. У вашего клона все еще есть ссылка 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
Нам не нужен псевдо-рефон HEAD и удалите его с помощью grep -v
. В остальном мы используем Perl для удаления префикса refs/remotes/origin/
и для каждого запускаем команду вида
$ git push -f origin refs/remotes/origin/BRANCH:BRANCH