Как найти/идентифицировать большие файлы/фиксации в истории Git?

У меня есть репозиторий git 300 МБ. Мои файлы с проверенными файлами весит 2 МБ, а репозиторий git - 298 МБ. Это в основном репозиторий с кодом, который не должен весить больше нескольких МБ.

Скорее всего, кто-то в какой-то момент совершил некоторые тяжелые файлы случайно (видео, огромные изображения и т.д.), а затем удалил их... но не из git, поэтому у нас есть история с бесполезными большими файлами. Как я могу отслеживать большие файлы в истории git? Есть более 400 коммитов, поэтому переход на один из них потребует много времени.

ПРИМЕЧАНИЕ: мой вопрос не о как удалить файл, но как найдите его в первую очередь.

Ответы

Ответ 1

В прошлом я нашел этот скрипт очень полезным для поиска больших (и неочевидных) объектов в репозитории git:


#!/bin/bash
#set -x 

# Shows you the largest objects in your repo pack file.
# Written for osx.
#
# @see https://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/
# @author Antony Stubbs

# set the internal field separator to line break, so that we can iterate easily over the verify-pack output
IFS=$'\n';

# list all objects including their size, sort by size, take top 10
objects='git verify-pack -v .git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head'

echo "All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file."

output="size,pack,SHA,location"
allObjects='git rev-list --all --objects'
for y in $objects
do
    # extract the size in bytes
    size=$(('echo $y | cut -f 5 -d ' ''/1024))
    # extract the compressed size in bytes
    compressedSize=$(('echo $y | cut -f 6 -d ' ''/1024))
    # extract the SHA
    sha='echo $y | cut -f 1 -d ' ''
    # find the objects location in the repository tree
    other='echo "${allObjects}" | grep $sha'
    #lineBreak='echo -e "\n"'
    output="${output}\n${size},${compressedSize},${other}"
done

echo -e $output | column -t -s ', '

Это даст вам имя объекта (SHA1sum) большого двоичного объекта, а затем вы можете использовать такой скрипт:

... чтобы найти коммит, который указывает на каждый из этих BLOB-объектов.

Ответ 2

🚀 Чертовски быстрый однострочный корпус 🚀

Этот сценарий оболочки отображает все объекты BLOB-объектов в хранилище, отсортированные от наименьшего к наибольшему.

Для моего примера репо он работал примерно в 100 раз быстрее, чем другие, найденные здесь.
В моей надежной системе Athlon II X4 она обрабатывает репозиторий ядра Linux с 5,6 миллионами объектов всего за минуту.

Базовый сценарий

git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| sed -n 's/^blob //p' \
| sort --numeric-sort --key=2 \
| cut -c 1-12,41- \
| $(command -v gnumfmt || echo numfmt) --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

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

...
0d99bb931299  530KiB path/to/some-image.jpg
2ba44098e28f   12MiB path/to/hires-image.png
bd1741ddce0d   63MiB path/to/some-video-1080p.mp4

Пользователи macOS: поскольку numfmt недоступен в macOS, вы можете либо пропустить последнюю строку и заняться необработанными размерами в байтах, либо brew install coreutils.

фильтрация

Для дальнейшей фильтрации вставьте любую из следующих строк перед строкой sort.

Чтобы исключить файлы, присутствующие в HEAD, вставьте следующую строку:

| grep -vF --file=<(git ls-tree -r HEAD | awk '{print $3}') \

Чтобы показать только файлы, размер которых превышает заданный размер (например, 1 МБ = 2 20 Б), вставьте следующую строку:

| awk '$2 >= 2^20' \

Выход для компьютеров

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

...
0d99bb93129939b72069df14af0d0dbda7eb6dba 542455 path/to/some-image.jpg
2ba44098e28f8f66bac5e21210c2774085d2319b 12446815 path/to/hires-image.png
bd1741ddce0d07b72ccf69ed281e09bf8a2d0b2f 65183843 path/to/some-video-1080p.mp4

Удаление файла

Для фактического удаления файла, проверьте этот SO вопрос по теме.

Ответ 3

Я нашел однострочное решение на вики-странице ETH Zurich Department of Physics (ближе к концу этой страницы). Просто сделайте git gc чтобы удалить устаревший мусор, а затем

git rev-list --objects --all \
  | grep "$(git verify-pack -v .git/objects/pack/*.idx \
           | sort -k 3 -n \
           | tail -10 \
           | awk '{print$1}')"

даст вам 10 самых больших файлов в хранилище.

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

GitExtensions 'Find large files' dialog

Ответ 4

Шаг 1 Запишите все файлы SHA1 в текстовый файл:

git rev-list --objects --all | sort -k 2 > allfileshas.txt

Шаг 2 Сортировка больших двоичных объектов с самых больших на маленькие и запись результатов в текстовый файл:

git gc && git verify-pack -v .git/objects/pack/pack-*.idx | egrep "^\w+ blob\W+[0-9]+ [0-9]+ [0-9]+$" | sort -k 3 -n -r > bigobjects.txt

Шаг 3а Объедините оба текстовых файла, чтобы получить информацию об имени файла /sha1/size:

for SHA in 'cut -f 1 -d\  < bigobjects.txt'; do
echo $(grep $SHA bigobjects.txt) $(grep $SHA allfileshas.txt) | awk '{print $1,$3,$7}' >> bigtosmall.txt
done;

Шаг 3b Если у вас есть имена файлов или пути, содержащие пробелы, попробуйте этот вариант шага 3a. Он использует cut вместо awk чтобы получить нужные столбцы вкл. пробелы от столбца 7 до конца строки:

for SHA in 'cut -f 1 -d\  < bigobjects.txt'; do
echo $(grep $SHA bigobjects.txt) $(grep $SHA allfileshas.txt) | cut -d ' ' -f'1,3,7-' >> bigtosmall.txt
done;

Теперь вы можете посмотреть файл bigtosmall.txt, чтобы решить, какие файлы вы хотите удалить из своей истории Git.

Шаг 4 Чтобы выполнить удаление (обратите внимание, что эта часть медленная, так как она собирается проверять каждый коммит в вашей истории на предмет данных о файле, который вы определили):

git filter-branch --tree-filter 'rm -f myLargeFile.log' HEAD

Источник

Шаги 1-3a были скопированы из поиска и очистки больших файлов из истории Git

РЕДАКТИРОВАТЬ

Статья была удалена где-то во второй половине 2017 года, но к ее архивной копии все еще можно получить доступ с помощью Wayback Machine.

Ответ 5

Вы должны использовать BFG Repo-Cleaner.

Согласно веб-сайту:

BFG - это более простая и быстрая альтернатива git -filter-branch для очистка плохих данных из истории хранилища Git:

  • Удаление сумасшедших больших файлов
  • Удаление паролей, учетных данных и других конфиденциальных данных

Классической процедурой для уменьшения размера репозитория будет:

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --strip-biggest-blobs 500 some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push

Ответ 6

Если вам нужен только список больших файлов, я бы хотел предоставить вам следующий однострочный (источник в renuo):

join -o "1.1 1.2 2.3" <(git rev-list --objects --all | sort) <(git verify-pack -v objects/pack/*.idx | sort -k3 -n | tail -5 | sort) | sort -k3 -n

Чей выход будет:

commit       file name                                  size in bytes

72e1e6d20... db/players.sql 818314
ea20b964a... app/assets/images/background_final2.png 6739212
f8344b9b5... data_test/pg_xlog/000000010000000000000001 1625545
1ecc2395c... data_development/pg_xlog/000000010000000000000001 16777216
bc83d216d... app/assets/images/background_1forfinal.psd 95533848

Последняя запись в списке указывает на самый большой файл в истории git.

Вы можете использовать этот вывод, чтобы убедиться, что вы не удаляете материал BFG, который вам понадобился бы в вашей истории.

Ответ 7

Если вы находитесь в Windows, вот PowerShell script, который будет печатать 10 самых больших файлов в вашем репозитории:

$revision_objects = git rev-list --objects --all;
$files = $revision_objects.Split() | Where-Object {$_.Length -gt 0 -and $(Test-Path -Path $_ -PathType Leaf) };
$files | Get-Item -Force | select fullname, length | sort -Descending -Property Length | select -First 10

Ответ 8

Попробуй git ls-files | xargs du -hs --threshold=1M git ls-files | xargs du -hs --threshold=1M.

Мы используем приведенную ниже команду в нашем конвейере CI, она останавливается, если находит в git-репозитории большие файлы:

test $(git ls-files | xargs du -hs --threshold=1M 2>/dev/null | tee /dev/stderr | wc -l) -gt 0 && { echo; echo "Aborting due to big files in the git repository."; exit 1; } || true

Ответ 9

Как я могу отслеживать большие файлы в истории git?

Начните с анализа, проверки и выбора основной причины. Используйте git-repo-analysis, чтобы помочь.

Вы также можете найти некоторое значение в подробных отчетах, созданных BFG Repo-Cleaner, которые можно запускать очень быстро, клонируя Цифровая капелька океана с пропускной способностью 10 Мбит/с.

Ответ 10

Я наткнулся на это по той же причине, что и все остальные. Но приведенные сценарии не совсем спомогли мне. Я сделал один, который является более гибридным из тех, что я видел, и теперь он живет здесь - https://gitlab.com/inorton/git-size-calc