Как удалить не связанные ссылки из моего репозитория git
У меня есть репозиторий GitHub с двумя ветками - master и release.
Ветвь релиза содержала бинарные дистрибутивные файлы, которые способствовали очень большому размеру репо (> 250 МБ), поэтому я решил все исправить.
Сначала я удалил ветку удаленного выпуска, через git push origin :release
Затем я удалил локальную ветку релиза. Сначала я попробовал git branch -d release
, но git сказал: "ошибка: ветвь" релиз "не является предком вашей текущей HEAD". что верно, так что я сделал git branch -D release
заставить его быть удаленным.
Но размер моего хранилища, как локально, так и на GitHub, все еще был огромен. Итак, я пробежал обычный список команд git, например git gc --prune=today --aggressive
без везения.
Следуя инструкциям Чарльза Бейли на SO 1029969, я смог получить список SHA1 для самых больших капель. Затем я использовал сценарий из SO 460331, чтобы найти капли... и пять самых больших не существуют, хотя меньшие капли найдены, так что я знаю, что скрипт работает.
Я думаю, что эти блоги - бинарные файлы из ветки релиза, и они каким-то образом остались после удаления этой ветки. Как правильно избавиться от них?
11 ответов
... и без дальнейших церемоний, могу я представить вам этот полезный скрипт, git-gc-all, гарантированно удаляющий весь ваш мусор git до тех пор, пока они не могут вызвать дополнительные переменные конфигурации:
git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 \
-c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@"
Вам также может понадобиться запустить что-то вроде этого, о, дорогой, мерзавец сложен!!
git remote rm origin
rm -rf .git/refs/original/ .git/refs/remotes/ .git/*_HEAD .git/logs/
git for-each-ref --format="%(refname)" refs/original/ | xargs -n1 --no-run-if-empty git update-ref -d
Я положил все это в сценарий, здесь:
http://sam.nipl.net/b/git-gc-all-ferocious
редактировать: вам также может понадобиться удалить некоторые теги, спасибо Zitrax:
git tag | xargs git tag -d
Как описано здесь, просто используйте
git reflog expire --expire-unreachable=now --all
git gc --prune=now
git reflog expire --expire-unreachable=now --all
удаляет все ссылки о недоступных коммитах в reflog
,
git gc --prune=now
удаляет коммиты сами.
Внимание: только используя git gc --prune=now
не будет работать, так как эти коммиты все еще упоминаются в reflog. Поэтому очистка рефлога является обязательной.
Как уже упоминалось в этом ответе, git gc
действительно может увеличить размер репо!
Смотрите также эту тему
Теперь в git есть механизм безопасности, позволяющий не удалять не связанные объекты сразу при запуске.
git gc
".
По умолчанию объекты, на которые нет ссылок, хранятся в течение 2 недель. Это сделано для того, чтобы упростить вам восстановление случайно удаленных веток или фиксаций или избежать гонки, в которой только что созданный объект в процессе нахождения, но еще не упомянутый, может быть удален с помощью 'git gc
'процесс работает параллельно.Таким образом, чтобы предоставить этот льготный период упакованным, но не связанным объектам, процесс переупаковки выталкивает эти не связанные объекты из пакета в их свободную форму, чтобы они могли быть состарены и в конечном итоге обрезаны.
Объектов, на которые нет ссылок, обычно не так много. Наличие 404855 объектов без ссылок довольно много, и отправка этих объектов в первую очередь через клон является глупой и полной тратой пропускной способности сети.Во всяком случае... Чтобы решить вашу проблему, вам просто нужно запустить
git gc
'с--prune=now
аргумент, чтобы отключить этот льготный период и сразу же избавиться от тех объектов, на которые нет ссылок (безопасно, только если в это же время не выполняются другие действия git, что должно быть легко обеспечить на рабочей станции).И кстати, используя
git gc --aggressive
'с более поздней версией git (или'git repack -a -f -d --window=250 --depth=250
")
Эта же тема упоминает:
git config pack.deltaCacheSize 1
Это ограничивает размер дельта-кэша одним байтом (фактически отключая его) вместо значения по умолчанию 0, что означает неограниченный. С этим я могу перепаковать этот репозиторий, используя выше
git repack
команда в системе x86-64 с 4 ГБ оперативной памяти и использованием 4 потоков (это четырехъядерное ядро). Использование резидентной памяти растет почти до 3,3 ГБ.Если ваша машина SMP и у вас недостаточно оперативной памяти, вы можете уменьшить количество потоков только до одного:
git config pack.threads 1
Кроме того, вы можете дополнительно ограничить использование памяти с помощью
--window-memory argument
кgit repack
".
Например, используя--window-memory=128M
следует поддерживать разумную верхнюю границу использования памяти дельта-поиска, хотя это может привести к менее оптимальному дельта-совпадению, если в репо содержится много больших файлов.
На фронте ветки фильтра, вы можете рассмотреть (с осторожностью) этот скрипт
#!/bin/bash
set -o errexit
# Author: David Underhill
# Script to permanently delete files/folders from your git repository. To use
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2
if [ $# -eq 0 ]; then
exit 0
fi
# make sure we're at the root of git repo
if [ ! -d .git ]; then
echo "Error: must run this script from the root of a git repository"
exit 1
fi
# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $files" HEAD
# remove the temporary history git-filter-branch otherwise leaves behind for a long time
rm -rf .git/refs/original/ && git reflog expire --all && git gc --aggressive --prune
git gc --prune=now
или низкий уровень git prune --expire now
,
Каждый раз, когда ваша голова движется, Git отслеживает это в reflog
, Если вы удалили коммиты, у вас все еще есть "висячие коммиты", потому что на них все еще ссылаются reflog
на ~30 дней. Это сеть безопасности, когда вы удаляете коммиты случайно.
Вы можете использовать git reflog
команда для удаления определенных коммитов, перепаковки и т. д., или просто команда высокого уровня:
git gc --prune=now
Ты можешь использовать git forget-blob
,
Использование довольно просто git forget-blob file-to-forget
, Вы можете получить больше информации здесь
Он исчезнет из всех коммитов в вашей истории, рефлогов, тэгов и т. Д.
Время от времени я сталкиваюсь с одной и той же проблемой, и каждый раз, когда мне приходится возвращаться к этому и другим постам, я автоматизировал этот процесс.
Кредиты для таких авторов, как Сэм Уоткинс
Перед тем как делать git filter-branch
а также git gc
, вы должны просмотреть теги, которые присутствуют в вашем репо. Любая реальная система, которая имеет автоматические теги для таких вещей, как непрерывная интеграция и развертывания, будет создавать нежелательные объекты, на которые все еще ссылаются эти теги, следовательно, gc
не можете удалить их, и вы все равно будете удивляться, почему размер репо все еще такой большой.
Лучший способ избавиться от всего ненужного - бежать git-filter
& git gc
а затем подтолкнуть мастера к новому голому репо. У нового голого репо будет зачищенное дерево.
Попробуйте использовать http://git-scm.com/docs/git-filter-branch - он не удаляет большие BLOB-объекты, но он может удалять большие файлы, которые вы указываете из всего репо. Для меня это уменьшает размер репо с сотен МБ до 12 МБ.
Чтобы добавить еще один совет, не забудьте использовать git remote prune для удаления устаревших веток ваших пультов перед использованием git gc
вы можете увидеть их с помощью git branch -a
Это часто полезно, когда вы получаете из github и разветвленных хранилищ...
Иногда причина, по которой "gc" не приносит особой пользы, заключается в том, что существует незаконченная перебазировка или тайник, основанный на старой фиксации.