Основы

Git LFS: как хранить большие файлы в Git-репозитории

Обновлено: · Skillaria.Top

Git LFS (Large File Storage) — расширение Git, которое хранит большие бинарные файлы на отдельном сервере, а в репозиторий кладёт только маленькие файлы-указатели. Клонирование становится быстрым, история не раздувается, а работа с файлами остаётся привычной: git add, commit и push.

Что такое Git LFS и зачем он нужен

Git LFS (Large File Storage) — официальное расширение Git для хранения больших файлов: видео, макетов PSD, датасетов, моделей нейросетей, игровых ассетов. Вместо самого файла в коммит попадает текстовый указатель размером около 130 байт, а содержимое уходит в отдельное LFS-хранилище на сервере. При checkout расширение подставляет настоящий файл в рабочую директорию, поэтому для вас всё выглядит как обычный Git.

Проблема, которую решает git lfs, в устройстве самого Git. Каждая версия каждого файла навсегда остаётся в истории, и при клонировании скачивается вся история целиком. Если вы десять раз поменяли видеоролик на 200 МБ, репозиторий весит уже около 2 ГБ, и каждый новый разработчик скачивает все десять версий, даже если ему нужна только последняя. Сжатие и дельты, которые хорошо работают для текста, на бинарных файлах почти бесполезны.

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

Как работает Git LFS изнутри

Механизм построен на фильтрах Git — clean и smudge. Когда вы делаете git add файла, который отслеживает LFS, срабатывает фильтр clean: он кладёт содержимое в локальный кэш .git/lfs/objects и передаёт в индекс указатель. При checkout фильтр smudge делает обратное: находит объект по хешу в кэше (или скачивает с сервера) и записывает настоящий файл.

Указатель выглядит так:

version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 209715200

Три строки: версия спецификации, SHA-256 содержимого и размер в байтах. Именно это хранится в истории Git, поэтому история остаётся лёгкой. При git push срабатывает pre-push хук: сначала по LFS API загружаются новые объекты, затем обычным протоколом отправляются коммиты.

Какие файлы отдавать LFS, определяет файл .gitattributes в корне репозитория. Он коммитится вместе с кодом, поэтому правила одинаковы у всей команды.

Как установить Git LFS

В Git для Windows расширение уже входит в установщик. На macOS и Linux его ставят пакетом:

# macOS (Homebrew)
brew install git-lfs

# Debian / Ubuntu
sudo apt install git-lfs

# Fedora
sudo dnf install git-lfs

После установки один раз для пользователя выполните:

git lfs install

Команда прописывает фильтры LFS в глобальный ~/.gitconfig и ставит хуки в текущий репозиторий, если вы внутри него. Проверить, что всё на месте, можно командой git lfs version, а подробную конфигурацию (адрес сервера, пути кэша) показывает git lfs env.

Как начать отслеживать большие файлы

Типичный сценарий для нового проекта:

git lfs track "*.psd"
git lfs track "*.mp4"
git lfs track "models/**"

git add .gitattributes
git add design/banner.psd
git commit -m "Добавить макет баннера через LFS"
git push origin main

Кавычки вокруг шаблона обязательны: без них оболочка сама раскроет *.psd в список файлов текущей папки, и правило получится не тем. После git lfs track в .gitattributes появится строка:

*.psd filter=lfs diff=lfs merge=lfs -text

Атрибут -text отключает преобразование переводов строк, которое испортило бы бинарный файл. Порядок важен: сначала правило track, потом git add файла. Если файл уже был добавлен обычным образом до появления правила, он остался в истории как обычный blob.

Как проверить, что файл действительно в LFS

git lfs ls-files
4d7a214614 * design/banner.psd
9c1e0b7a3f * video/intro.mp4

git lfs status

git lfs ls-files показывает файлы текущего коммита, хранящиеся в LFS. Звёздочка означает, что содержимое скачано, дефис — что в рабочей копии лежит только указатель. Список шаблонов отслеживания выводит git lfs track без аргументов, а убрать правило можно через git lfs untrack "*.psd".

Клонирование и получение файлов

Обычный git clone работает с LFS прозрачно: если расширение установлено, большие файлы скачиваются автоматически. Если же у коллеги LFS не установлен, в рабочей копии он увидит текстовые указатели вместо картинок — это самый частый симптом «у меня вместо PSD какой-то текст». Лечится установкой и командой:

git lfs install
git lfs pull

git lfs pull скачивает объекты для текущего коммита и подставляет их в рабочую директорию. Отдельно существует git lfs fetch — он только качает в кэш, не трогая файлы. С флагом --all он загружает объекты для всех ссылок, что пригодится для полного бэкапа или переноса на другой сервер.

Как клонировать без больших файлов

В CI или когда нужен только код, скачивание гигабайт ассетов лишнее. Переменная окружения отключает smudge-фильтр:

GIT_LFS_SKIP_SMUDGE=1 git clone https://example.com/team/game.git
cd game
git lfs pull --include="textures/ui/**"

Репозиторий клонируется с указателями, а затем вы выборочно забираете нужные файлы через --include (есть и --exclude). Это заметно ускоряет сборки в пайплайнах.

Как перенести существующие файлы в Git LFS

Частая ситуация: репозиторий уже раздулся, большие файлы лежат в истории. Команда git lfs track на прошлое не действует — она влияет только на новые коммиты. Чтобы переписать историю, используйте git lfs migrate.

Сначала оцените, что занимает место:

git lfs migrate info --everything --top=10

Затем перенесите нужные типы во всех ветках:

git lfs migrate import --include="*.psd,*.mp4" --everything
git push --force --all
git push --force --tags

Миграция переписывает каждый коммит, где встречались эти файлы, значит меняются все хеши. Это та же история, что с rebase опубликованных веток: всех участников нужно предупредить, после принудительного push они должны заново клонировать репозиторий или жёстко сбросить свои ветки. Перед миграцией сделайте резервную копию (git clone --mirror).

Если переписывать историю нельзя, есть мягкий вариант: git lfs migrate import --no-rewrite путь/к/файлу. Он создаёт новый коммит, который переводит файлы в LFS с этого момента. Старые версии останутся в истории, но рост репозитория прекратится.

Блокировка файлов: защита от конфликтов в бинарниках

Два дизайнера правят один PSD — и Git не сможет слить их изменения, одна работа будет потеряна. Для таких файлов в LFS есть блокировки. Помечаете тип как блокируемый:

git lfs track "*.psd" --lockable

В .gitattributes добавится атрибут lockable, и такие файлы в рабочей копии станут доступны только для чтения, пока вы их не заблокируете:

git lfs lock design/banner.psd
git lfs locks
design/banner.psd	anna	ID:123

# после push изменений
git lfs unlock design/banner.psd

Пока файл заблокирован, push изменений в него от другого человека будет отклонён. Блокировки поддерживает сервер, поэтому они работают на крупных Git-хостингах, но на самописном сервере их может не быть. Администратор может снять чужую блокировку через git lfs unlock --force.

Где хранятся LFS-объекты и сколько это стоит

LFS-объекты живут на сервере, который поддерживает LFS API. Его реализуют популярные Git-хостинги и self-hosted решения, а также отдельные серверы. У облачных хостингов есть лимиты на объём хранилища и трафик LFS, и они отличаются у разных сервисов и тарифов — проверяйте актуальные условия своей платформы до того, как класть туда датасеты на сотни гигабайт.

Учтите, что трафик считается при каждом скачивании: CI, который на каждый коммит клонирует репозиторий с LFS-файлами, может выбрать лимит быстрее, чем люди. Кэшируйте .git/lfs между сборками или используйте GIT_LFS_SKIP_SMUDGE.

Локально кэш тоже растёт. Команда git lfs prune удаляет старые объекты, которые уже есть на сервере и не нужны для текущих и недавних коммитов.

Когда Git LFS подходит, а когда нет

СитуацияLFS подходит?Комментарий
Игровые ассеты, макеты, аудио, видеоДаКлассический случай: бинарники, которые часто меняются
Модели ML и средние датасеты рядом с кодомДа, с оглядкой на квотыДля очень больших данных удобнее специализированные инструменты версионирования данных
Скомпилированные артефакты сборкиНетИх место в реестре артефактов или релизах, а не в Git
Зависимости (node_modules, vendor)НетУстанавливаются менеджером пакетов, добавьте их в .gitignore
Большие текстовые файлы (SQL-дампы, CSV)ЗависитТекст Git хранит дельтами эффективно; LFS нужен, если файлы огромные и почти не читаются в diff
Секреты и приватные ключиНикогдаLFS не шифрует данные, это не хранилище секретов

Типичные ошибки и как их исправить

В рабочей копии вместо файла текстовый указатель

LFS не установлен или клон сделан с GIT_LFS_SKIP_SMUDGE=1. Выполните git lfs install и git lfs pull.

Файл попал в историю мимо LFS

Правило track добавили после git add. Если коммит ещё не отправлен, уберите файл из индекса (git rm --cached файл), убедитесь, что правило в .gitattributes есть, и добавьте заново. Если уже отправлен — git lfs migrate import. Найти такие файлы помогает git lfs fsck --pointers.

Push отклоняется из-за размера файла

Многие хостинги ограничивают размер одного объекта в обычном Git. Сообщение вроде «this exceeds the file size limit» значит, что файл надо было отдать LFS. Перепишите последний коммит или историю, как описано выше, — простой коммит «удалить файл» не поможет, он останется в предыдущих коммитах.

После git lfs migrate у коллег всё сломалось

Их локальные ветки основаны на старых хешах. Надёжнее всего заново клонировать репозиторий; при наличии незапушенной работы — перенести её через cherry-pick на новые ветки.

Шпаргалка команд Git LFS

КомандаЧто делает
git lfs installНастраивает фильтры и хуки
git lfs track "*.ext"Добавляет шаблон в .gitattributes
git lfs untrack "*.ext"Убирает шаблон
git lfs ls-filesФайлы в LFS для текущего коммита
git lfs pullСкачать и подставить объекты
git lfs fetch --allСкачать объекты всех ссылок в кэш
git lfs migrate import --include="..." --everythingПеренести файлы из истории в LFS
git lfs lock / unlock / locksРабота с блокировками
git lfs pruneОчистить локальный кэш от старых объектов
git lfs envДиагностика настроек

Итог

Git LFS выносит большие бинарные файлы из истории в отдельное хранилище, оставляя в коммитах лёгкие указатели. Главное правило — настраивать git lfs track до первого коммита больших файлов, коммитить .gitattributes и следить за квотами хостинга. Если файлы уже в истории, поможет git lfs migrate, но это переписывание истории со всеми последствиями. Работу с историей, rebase и другими продвинутыми инструментами Git мы разбираем на практике в курсе по Git.

Частые вопросы

Git LFS бесплатный?

Само расширение — открытое и бесплатное. Платить можно за хранилище и трафик у Git-хостинга, если превысить бесплатные лимиты вашего тарифа.

Какой размер файла считать большим для LFS?

Жёсткой границы нет; обычно в LFS отправляют бинарники от нескольких мегабайт, которые часто меняются. Текстовые файлы даже крупного размера Git хранит эффективно и без LFS.

Можно ли отказаться от Git LFS и вернуть файлы в обычный Git?

Да, командой git lfs migrate export --include="*.psd" --everything, которая переписывает историю обратно. После этого нужно убрать правила из .gitattributes и сделать force push.

Работает ли git diff для файлов в LFS?

Git покажет изменение указателя, а не содержимого, потому что файлы бинарные. Для картинок и документов сравнение делают внешними инструментами.

Нужен ли LFS каждому участнику команды?

Да, иначе у участника без расширения в рабочей копии будут указатели вместо файлов, а его коммиты могут случайно добавить большие файлы мимо LFS.

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

Эта тема подробно разобрана с практикой в курсе «Git с нуля до уверенного разработчика».

Перейти к курсу