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

89

Я случайно добавил, зафиксировал и отправил огромный двоичный файл с моей последней фиксацией в репозиторий Git.

Как я могу заставить Git удалить объект (ы), который был / был создан для этого коммита, чтобы мой .gitкаталог снова уменьшился до нормального размера?

Изменить : Спасибо за ваши ответы; Я пробовал несколько решений. Ни один не работал. Например, тот, что был на GitHub, удалил файлы из истории, но .gitразмер каталога не уменьшился:

$ BADFILES=$(find test_data -type f -exec echo -n "'{}' " \;)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $BADFILES" HEAD
Rewrite 14ed3f41474f0a2f624a440e5a106c2768edb67b (66/66)
rm 'test_data/images/001.jpg'
[...snip...]
rm 'test_data/images/281.jpg'
Ref 'refs/heads/master' was rewritten

$ git log -p # looks nice

$ rm -rf .git/refs/original/
$ git reflog expire --all
$ git gc --aggressive --prune
Counting objects: 625, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (598/598), done.
Writing objects: 100% (625/625), done.
Total 625 (delta 351), reused 0 (delta 0)

$ du -hs .git
174M    .git
$ # still 175 MB :-(
Йонас Х.
источник
13
Напоминаю модераторам, что этот вопрос на 100% принадлежит SO, а не суперпользователю.
VonC
Как уже упоминалось здесь ( stackoverflow.com/questions/685319/… ), вы пробовали перепаковать после своего gc? git-repack -aза которым следует, git-prune-packedнапример. См. Blog.felipebalbi.com/2007/12/19/…
VonC
2
@Jonas: а что, если после всего этого вы клонируете свое репо? Вы бы тогда получить клон с желаемой уменьшенного размера?
VonC
1
@Jonas: после того, как все , что вы сделали ( filter-branch, gc, repack...), нет, вы не должны видеть любой плохой фиксации на всех. Это признак того, что уборка прошла не так, как ожидалось.
VonC

Ответы:

127

Я ответил на это в другом месте и скопирую здесь, так как горжусь этим!

... и без лишних слов, могу я представить вам этот полезный скрипт 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 "$@"

Может оказаться полезным параметр --aggressive.

ПРИМЕЧАНИЕ: это удалит ВСЕ элементы, на которые нет ссылок, так что не приходите ко мне со слезами на глазах, если вы позже решите, что хотите сохранить некоторые из них!

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

Я записал все это в скрипт, вот здесь:

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

Сэм Уоткинс
источник
Как и в stackoverflow.com/questions/1904860/… , снова +1 вам.
VonC
18
отлично: D мой злой план получить больше очков путем клонирования ответов сработал !! 1;)
Сэм Уоткинс
Да! Это сработало, но мне пришлось запустить полный сценарий. Запустить только команду gc (с параметрами конфигурации) было недостаточно.
Даниэль
4
От 102 м до 160 км .. эффективный и разрушительный
Пруссван
4
Большое спасибо за сценарий! Дополнительная информация: xargsкоманда выдает ошибку в OS X из-за нераспознанной опции. Самое простое решение: установите GNU xargs через homebrew brew install findutilsи замените xargsна gxargs.
qqilihq
26

Ваш git reflog expire --allневерен. Он удаляет записи журнала ссылок, которые старше, чем время истечения срока действия, которое по умолчанию составляет 90 дней. Используйте git reflog expire --all --expire=now.

Мой ответ на аналогичный вопрос касается проблемы действительно очистки неиспользуемых объектов из репозитория.

Джош Ли
источник
18

1) Удалите файл из репозитория git (а не файловую систему):

  • git rm --cached path/to/file

2) Уменьшите репо, используя:

  • git gc,

  • или git gc --aggressive

  • или git prune

или комбинация вышеперечисленного, как предлагается в этом вопросе: уменьшить размер репозитория git

Джейми
источник
10

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

Если вы хотите, чтобы двоичный файл был доступен в репо для других людей, тогда нет реального способа делать то, что вы хотите. Это почти все или ничего.

Daenyth
источник
8

Ключ для меня оказался запущен, git repack -A -d -fа затем git gcуменьшен размер единственного пакета git, который у меня был.

Эндрю Чарнески
источник
6

Эй!

Git получает только те объекты, которые ему действительно нужны, при клонировании репозиториев (если я правильно понимаю)

Таким образом, вы можете исправить последнюю фиксацию, удалив файл, добавленный по ошибке, а затем отправить свои изменения в удаленный репозиторий (с параметром -f, чтобы перезаписать старую фиксацию на сервере)

Затем, когда вы создаете новый клон этого репо, его каталог .git должен быть таким же маленьким, как и до фиксации большого файла (ов).

При желании, если вы также хотите удалить ненужные файлы с сервера, вы можете удалить репозиторий на сервере и отправить новую клонированную копию (с полной историей)

у-фока
источник
4
git filter-branch --index-filter 'git rm --cached --ignore-unmatch Filename' --prune-empty -- --all

Не забудьте изменить Filenameтот, который хотите удалить из репозитория.

Мартин
источник
0

В 2020 году документация для git-filter-branch не поощряет его использование и рекомендует использовать альтернативу, такую ​​как git-filter-repo . Также может использоваться вместо BFG. .

Обратите внимание, что глава о перезаписи истории в книге git не обновлялась. Также нет рекомендаций GitHub по удалению конфиденциальных данных.

user2465896
источник