Чтобы найти самые большие файлы, хранящиеся в достижимой истории Git репозитория на macOS, откройте Терминал, перейдите в репозиторий и передайте список объектов Git через конвейер в git cat-file и sort. Это выведет несжатый размер каждого блоба (blob) в байтах и подсказку пути к файлу. Таким образом можно обнаружить файлы, которые были удалены или заменены, но остались в коммитах, достижимых из веток или тегов.

Запуск сканирования истории из Терминала

В Терминале используйте команду cd, чтобы перейти в репозиторий. Заключите путь к папке в кавычки, если он содержит пробелы. Затем выполните:

git rev-list --objects --all |
  git cat-file --batch-check='%(objecttype) %(objectsize) %(objectname) %(rest)' |
  awk '$1 == "blob"' |
  sort -k2,2nr |
  head -20

Результат будет отсортирован по убыванию размера. В каждой строке отображается тип объекта, размер в байтах, идентификатор объекта (object ID) и, если Git предоставляет эти данные, подсказка пути. Команда git rev-list --objects --all обходит объекты, на которые ссылаются коммиты, достижимые из ссылок (refs), таких как локальные ветки и теги; git cat-file --batch-check сообщает тип и размер каждого объекта. Конвейер фильтрует только блобы — объекты, хранящие содержимое файлов. В документации Git по rev-list описан обход объектов и их именование, а в документации по cat-file описан пакетный вывод размера и типа.

Команда sort -k2,2nr использует встроенную в macOS утилиту sort для численной сортировки в обратном порядке по второму полю, разделенному пробелами (размеру в байтах). Команда head -20 ограничивает вывод 20 строками; измените число или удалите эту последнюю строку, чтобы увидеть больше. Команда только считывает данные репозитория. Она не изменяет коммиты или файлы.

Внимательно интерпретируйте результаты

Строка идентифицирует объект-блог (blob), а не обязательно файл, присутствующий в рабочем дереве в данный момент. Большой объект может относиться к старой версии файла, а подсказка пути не является полным историческим индексом путей: в документации Git указано, что при использовании --objects имена являются лишь подсказками, могут быть изменены из-за символов перевода строки, и если у объекта есть несколько имен, может отображаться только одно из них. Рассматривайте указанный путь как зацепку, а затем проверяйте соответствующие коммиты, чтобы подтвердить, когда и где появилось это содержимое. В примечаниях Git к именам объектов в rev-list объясняются эти ограничения.

Это сканирование охватывает объекты, достижимые из ссылок, найденных с помощью --all, а не каждый объект, который физически может оставаться в базе данных объектов. Чтобы проверить локальное хранилище объектов, включая недостижимые объекты, выполните:

git cat-file --batch-all-objects \
  --batch-check='%(objecttype) %(objectsize) %(objectname)' |
  awk '$1 == "blob"' |
  sort -k2,2nr |
  head -20

Параметр --batch-all-objects обходит все объекты в репозитории и альтернативных хранилищах объектов, включая объекты, недостижимые из ссылок. Эта вторая команда опускает пути к файлам, поэтому для дальнейшего исследования используйте идентификатор объекта (object ID). В документации по cat-file отмечается как более широкий охват объектов, так и то, что каждый объект отображается один раз, даже если он сохранен несколько раз.

Размер блоба не равен занимаемому месту на диске

Выводимый параметр objectsize — это несжатый размер объекта Git. Git может сжимать объекты или сохранять их в виде дельт (разностей) внутри pack-файлов, поэтому большой блоб не обязательно занимает именно такой объем дискового пространства. Для общего обзора использования хранилища выполните git count-objects -vH; его поле size-pack сообщает размер упакованных данных, а остальные поля обобщают информацию о свободных (loose) объектах и связанном хранилище. Эти показатели описаны в руководстве Git по count-objects. Чтобы проверить размеры упакованных объектов и сведения о дельтах, команда git verify-pack -v выводит список размеров каждого упакованного объекта и его размер в pack-файле, но для этого требуется соответствующий файл .idx. Этот вывод определен в руководстве по verify-pack.

Если вы обнаружили большой файл в истории

Сначала определите, в чем заключается ваша задача: понять текущее состояние рабочей копии (checkout) или уменьшить историю репозитория. Если вас интересует только текущая версия, проверьте файлы в Finder или используйте вывод списка файлов с размерами в Терминале; сканирование истории решает другую задачу, выполняя поиск по достижимым объектам Git.

Если большой файл необходимо удалить из всех ревизий, простого удаления в новом коммите недостаточно — старые копии останутся в истории. Перезапись истории меняет идентификаторы коммитов и затрагивает других пользователей репозитория, поэтому согласуйте свои действия перед выполнением и сохраните резервную копию. Проект git-filter-repo предлагает режим анализа только для чтения, git filter-repo --analyze, который создает отчеты, помогающие решить, что именно следует отфильтровать; в режиме анализа он не выполняет перезапись. В документации проекта описана опция анализа и содержится предупреждение о том, что фильтрация приводит к перезаписи истории.

Первый конвейер команд — это практичная отправная точка, когда цель состоит в том, чтобы найти самое большое содержимое файлов в истории локального репозитория. Используйте сканирование всех объектов, когда значение имеют недостижимые остаточные данные, и сопоставляйте размеры объектов Git с данными о pack-хранилище, прежде чем связывать использование дискового пространства с конкретным блобом.

Источники