Как удалить не связанные ссылки из моего репозитория 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, Вы можете получить больше информации здесь

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

Он исчезнет из всех коммитов в вашей истории, рефлогов, тэгов и т. Д.

Время от времени я сталкиваюсь с одной и той же проблемой, и каждый раз, когда мне приходится возвращаться к этому и другим постам, я автоматизировал этот процесс.

Кредиты для таких авторов, как Сэм Уоткинс

Перед тем как делать 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" не приносит особой пользы, заключается в том, что существует незаконченная перебазировка или тайник, основанный на старой фиксации.

пытаться:

git gc --prune="0 дней"

смотреть на:

https://gist.github.com/verkruemelt/9245775

Другие вопросы по тегам