Как удалить неопубликованные капли из моего репозитория git

У меня есть репо GitHub, у которого было две ветки - мастер и релиз.

В ветки релиза были бинарные файлы дистрибутива, которые вносили свой вклад в очень большой размер репо ( > 250 МБ), поэтому я решил очистить вещи.

Сначала я удалил ветвь удаленного выпуска, git push origin :release

Затем я удалил ветвь локального выпуска. Сначала я попробовал git branch -d release, но git said "error: релиз ветки не является предком вашего текущего HEAD." это правда, поэтому я сделал git branch -d release, чтобы он был удален.

Но размер моего репозитория, как локально, так и на GitHub, по-прежнему был огромным. Итак, я пропустил обычный список команд git, например git gc --prune=today --aggressive, без везения.

Следуя инструкциям Чарльза Бейли в SO 1029969, мне удалось получить список SHA1 для самых больших капель. Затем я использовал script из SO 460331, чтобы найти капли... и пять самых больших не существуют, хотя найдены небольшие капли, поэтому я знаю, script работает.

Я думаю, что эти блоги - это двоичные файлы из ветки релиза, и они как-то ушли после удаления этой ветки. Какой правильный способ избавиться от них?

Ответ 1

... и без лишнего шума, могу ли я представить вам этот полезный script, 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 "[email protected]"

Возможно, будет полезен параметр -агрессивный.

Возможно, вам также понадобится запустить что-то вроде этого сначала, о, дорогая, git сложно!

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

Я положил все это в script, здесь:

http://sam.nipl.net/b/git-gc-all-ferocious

edit: Вам также может потребоваться удалить некоторые теги, спасибо Zitrax:

git tag | xargs git tag -d

Ответ 2

Как описано здесь, просто используйте

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 является обязательной.

Ответ 3

Как упоминалось в этом SO-ответе, git gc может фактически увеличить размер репо!

См. также этот поток

Теперь git имеет механизм безопасности для немедленного удаления объектов без ссылок при запуске 'git gc'.
По умолчанию объекты без ссылок сохраняются в течение 2 недель. Это поможет вам восстановить случайно удаленные ветки или коммиты или избежать гонки, когда только что созданный объект в процессе существования, но еще не упомянутый, может быть удален процессом "git gc", выполняющимся параллельно.

Таким образом, чтобы предоставить этот льготный период для упакованных, но не привязанных к нему объектов, процесс переупаковки выталкивает эти неопубликованные объекты из пакета в их свободную форму, чтобы они могли быть постаревшими и в конечном итоге обрезками. Объекты, становящиеся неопубликованными, обычно не так много. Наличие 404855 объектов без ссылок довольно много, и отправка этих объектов в первую очередь с помощью клона глупа и полная потеря полосы пропускания сети.

В любом случае... Чтобы решить вашу проблему, вам просто нужно запустить 'git gc' с аргументом --prune=now, чтобы отключить этот льготный период и немедленно избавиться от этих объектов без ссылок (безопасно, только если нет других git действия происходят одновременно, что должно быть легко обеспечить на рабочей станции).

И BTW, используя '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 должно содержать разумную верхнюю границу дельта использование памяти поиска, хотя это может привести к менее оптимальному сочетанию треугольников, если репо содержит много больших файлов.


На фронте фильтра-ветки вы можете рассмотреть (с осторожным) этот script

#!/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 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
[email protected]
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

Ответ 4

git gc --prune=now или низкий уровень git prune --expire now.

Ответ 5

Каждый раз, когда ваш HEAD перемещается, git отслеживает это в reflog. Если вы удалили фиксации, у вас все еще есть "оборванные коммиты", потому что они по-прежнему ссылаются на reflog на ~ 30 дней. Это защитная сетка, когда вы удаляете фиксации случайно.

Вы можете использовать команду git reflog удалить определенные коммиты, переупаковать и т.д. или просто команду высокого уровня:

git gc --prune=now

Ответ 6

Вы можете использовать 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/

Он исчезнет из всех коммитов в вашей истории, reflog, тегов и т.д.

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

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

Ответ 7

Попробуйте использовать git-filter-branch - он не удаляет большие капли, но может удалять большие файлы, которые вы указываете из всего репо. Для меня это уменьшает размер репо от сотен МБ до 12 МБ.

Ответ 8

Прежде чем делать git filter-branch и git gc, вы должны просмотреть теги, которые присутствуют в вашем репо. Любая реальная система, которая имеет автоматическую маркировку для таких вещей, как непрерывная интеграция и развертывание, сделает ненужные объекты по-прежнему упомянутыми этими тегами, поэтому gc не может их удалить, и вы все равно будете задаваться вопросом, почему размер репо по-прежнему остается таким большим.

Лучший способ избавиться от всех ненужных материалов - запустить git-filter и git gc, а затем нажать master для нового голого репо. У нового голого репо будет очищенное дерево.

Ответ 9

Чтобы добавить еще один совет, не забудьте использовать git удаленное удаление, чтобы удалить устаревшие ветки ваших пультов перед использованием git gc

вы можете увидеть их с помощью git branch -a

Это часто полезно при извлечении из github и раздвоенных репозиториев...

Ответ 10

Иногда причина, по которой "gc" не приносит большой пользы, заключается в том, что существует незавершенная переформатирование или stash на основе старой фиксации.