Столкнулся с такой ситуацией: кто-то, когда-то создал архив, весом около 2гб, далее, кто-то добавил этот файл в git, затем архив конечно же удалился, а про git забыли, поэтому на момент моего вторжения git весил около 2.7гб.
!!! Проверяем файл .git/packed-refs на наличие строчки с удаленным репозитарием, например: refs/remotes/origin/master, и если такая есть, удаляем.
Для начала, потребовалось установить, что же это был за файл, собираем мусор в бд:
git gc
Counting objects: 457, done. Delta compression using 2 threads. Compressing objects: 100% (457/457), done. Writing objects: 100% (457/457), done. Total 457 (delta 250), reused 0 (delta 0)
Чтобы быстро узнать, сколько у нас занято места, можно воспользоваться командой count-objects
:
git count-objects -v
count: 20 size: 11 in-pack: 4411 packs: 1 size-pack: 2716918 prune-packable: 0 garbage: 0
Запись size-pack
— это размер упакованных файлов в килобайтах.
Найдём файл, который занимает много места. При вызове git gc
все объекты упаковываются в один файл, но, несмотря на это, определить самые крупные файлы можно, запустив служебную команду git verify-pack
, и отсортировав её вывод по третьей колонке, в которой записан размер файла. К тому же, так как нас интересуют только самые крупные файлы, оставим только последние несколько строк, направив вывод команде tail
:
git verify-pack -v .git/objects/pack/pack-#HASH_CODE#.pack | sort -k 3 -n | tail -3
e3f094f522629ae358806b17daf78246c27c007b blob 1486 734 4667 05408d195263d853f09dca71d55116663690c27c blob 12908 3478 1189 7a9eb2fba2b1811321254ac360970fc169ba2330 blob 2056716 2056872 5401
Большой объект в самом внизу. Для того чтобы узнать, что это за файл, воспользуемся командой rev-list
. Если передать ей ключ --objects
, то она выдаст хеши всех коммитов, а также хеши объектов и соответствующие им имена файлов. Воспользуемся этим для определения имени выбранного объекта:
git rev-list --objects --all | grep #HASH_CODE#
7a9eb2fba2b1811321254ac360970fc169ba2330 git.tbz2
Теперь необходимо удалить данный файл из всех деревьев в прошлом по истории. Легко получить все коммиты, которые меняли данный файл:
git log --pretty=oneline --branches -- git.tbz2
da3f30d019005479c99eb4c3406225613985a1db oops - removed large tarball 6df764092f3e7c8f5f94cbe08ee5cf42e92a0289 added git tarball
Необходимо переписать все коммиты, начиная с 6df76
для полного удаления данного файла. Для этого воспользуемся командой filter-branch
:
git filter-branch --index-filter 'git rm --cached --ignore-unmatch git.tbz2'
Rewrite 6df764092f3e7c8f5f94cbe08ee5cf42e92a0289 (1/2)rm 'git.tbz2' Rewrite da3f30d019005479c99eb4c3406225613985a1db (2/2) Ref 'refs/heads/master' was rewritten
Теперь наша история не содержит ссылок на данный файл. Однако, в reflog и в новом наборе ссылок, добавленном Git’ом в .git/refs/original
после выполнения filter-branch
, ссылки на него всё ещё присутствуют. Поэтому необходимо их удалить, а потом переупаковать базу. Необходимо избавиться от всех возможных ссылок на старые коммиты перед переупаковкой:
rm -rf .git/refs/original rm -rf .git/logs/
Делаем все не привязанные объекты истекшими по времени
git reflog expire --all --expire='0 days'
Проверяем на наличие не привязанных объектов
git fsck --full --unreachable
Производит переупаковку с удалением не привязанных объектов
git repack -A -d
И удаляем эти объекты
git prune