Управление большими двоичными файлами с помощью Git

Я ищу мнения о том, как обрабатывать большие двоичные файлы, от которых зависит мой исходный код (веб-приложение). В настоящее время мы обсуждаем несколько альтернатив:

  1. Скопируйте двоичные файлы вручную.
    • Pro: Не уверен.
    • Против: я категорически против этого, так как это увеличивает вероятность ошибок при настройке нового сайта / переносе старого. Создает еще одно препятствие, чтобы принять.
  2. Управляйте ими всеми с помощью Git.
    • Pro: Удаляет возможность "забыть" скопировать важный файл
    • Противоположность: раздувает хранилище и снижает гибкость управления базой кода, а проверки, клоны и т. Д. Займут довольно много времени.
  3. Отдельные репозитории.
    • Pro: извлечение / клонирование исходного кода выполняется быстро, как всегда, и изображения должным образом архивируются в своем собственном хранилище.
    • Против: Удаляет простоту наличия единственного репозитория Git в проекте. Это, безусловно, вводит некоторые другие вещи, о которых я не думал.

Что вы думаете об этом?

Также: есть ли у кого-нибудь опыт работы с несколькими репозиториями Git и управления ими в одном проекте?

Файлы являются изображениями для программы, которая генерирует PDF-файлы с этими файлами. Файлы будут меняться не очень часто (как в годах), но они очень важны для программы. Программа не будет работать без файлов.

13 ответов

Решение

Если программа не работает без файлов, кажется, что разбивать их на отдельные репозитории - плохая идея. У нас есть большие тестовые наборы, которые мы разбиваем на отдельные репозитории, но это действительно "вспомогательные" файлы.

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

Вот хорошее введение в подмодули из Git Book.

Недавно я обнаружил git-annex, который я нахожу потрясающим. Он был разработан для эффективного управления большими файлами. Я использую его для своих фото / музыкальных (и т.д.) коллекций. Разработка git-приложения очень активна. Содержимое файлов может быть удалено из репозитория Git, Git отслеживает только древовидную иерархию (через символические ссылки). Тем не менее, чтобы получить содержимое файла, необходимо выполнить второй шаг после извлечения / нажатия, например:

$ git annex add mybigfile
$ git commit -m'add mybigfile'
$ git push myremote
$ git annex copy --to myremote mybigfile ## This command copies the actual content to myremote
$ git annex drop mybigfile ## Remove content from local repo
...
$ git annex get mybigfile ## Retrieve the content
## or to specify the remote from which to get:
$ git annex copy --from myremote mybigfile

Доступно много команд, и на сайте есть отличная документация. Пакет доступен в Debian.

Другое решение, начиная с апреля 2015 года, - Git Large File Storage (LFS) (от GitHub).

Он использует git-lfs (см. https://git-lfs.github.com/) и протестирован с сервером, поддерживающим его: lfs-test-server:
Вы можете хранить метаданные только в git-репо, а большой файл - в другом месте.

https://cloud.githubusercontent.com/assets/1319791/7051226/c4570828-ddf4-11e4-87eb-8fc165e5ece4.gif

Взгляните на git bup, который является расширением Git для разумного хранения больших двоичных файлов в репозитории Git.

Вы хотели бы иметь его в качестве подмодуля, но вам не придется беспокоиться о том, что хранилище будет трудно обрабатывать. Один из примеров их использования - хранение образов виртуальных машин в Git.

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

Ваш пробег может отличаться.

Вы также можете использовать мерзавец. Мне нравится, что это зависит только от стокового Python и rsync, Он также поддерживает обычный рабочий процесс Git со следующими понятными командами:

git fat init
git fat push
git fat pull

Кроме того, вам необходимо зарегистрировать файл.gitfat в своем хранилище и изменить свои.gitattributes, указав нужные вам расширения файлов. git fat управлять.

Вы добавляете двоичный файл, используя обычный git add что в свою очередь вызывает git fat основанный на ваших правилах gitattributes.

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

ОБНОВЛЕНИЕ: не используйте git-fat, если вы используете мост Git-SVN. Это приведет к удалению двоичных файлов из вашего хранилища Subversion. Однако, если вы используете чистый Git-репозиторий, он прекрасно работает.

Я бы использовал подмодули (как Pat Notz) или два разных репозитория. Если вы будете слишком часто изменять ваши двоичные файлы, я постараюсь свести к минимуму влияние огромного хранилища, очищающего историю:

У меня была очень похожая проблема несколько месяцев назад: ~21 ГБ MP3-файлов, несекретных (плохие имена, плохие id3, не знаю, нравится ли мне этот MP3-файл или нет...), и реплицированных на трех компьютерах.

Я использовал внешний жесткий диск с основным репозиторием Git и клонировал его на каждый компьютер. Затем я начал классифицировать их привычным образом (толкание, вытягивание, объединение... удаление и переименование много раз).

В итоге у меня было всего ~6 ГБ файлов MP3 и ~83 ГБ в каталоге.git. я использовал git-write-tree а также git-commit-tree создать новый коммит, без предков коммитов, и начал новую ветку, указывающую на этот коммит. "Журнал Git" для этой ветви показал только один коммит.

Затем я удалил старую ветку, сохранил только новую ветку, удалил ref-logs и запустил "git prune": после этого мои папки.git весили всего ~6 ГБ...

Вы можете время от времени "очищать" огромное хранилище одним и тем же способом: ваш "мерзавец" будет быстрее.

Решение, которое я хотел бы предложить, основано на бесхозных ветвях и небольшом злоупотреблении механизмом тегов, отныне именуемом * Бинарное хранилище бесхозных тегов (OTABS)

TL; DR 12-01-2017 Если вы можете использовать LFS от github или какую-либо другую стороннюю компанию, вам обязательно следует. Если не можете, тогда читайте дальше. Имейте в виду, это решение является взломом и должно рассматриваться как таковое.

Желательные свойства ОТАБС

  • это чисто решение git and git only - оно выполняет свою работу без какого-либо стороннего программного обеспечения (например, git-annex) или сторонней инфраструктуры (например, LFS github).
  • он эффективно хранит двоичные файлы, то есть не раздувает историю вашего хранилища.
  • git pull а также git fetch, в том числе git fetch --all по-прежнему эффективна полоса пропускания, т.е. по умолчанию не все большие двоичные файлы извлекаются из удаленного узла.
  • это работает на Windows.
  • он хранит все в одном репозитории git.
  • это позволяет удалять устаревшие двоичные файлы (в отличие от bup).

Нежелательные свойства ОТАБС

  • это делает git clone потенциально неэффективно (но не обязательно, в зависимости от вашего использования). При развертывании этого решения вам, возможно, придется посоветовать своим коллегам использовать git clone -b master --single-branch <url> вместо git clone, Это потому, что git clone по умолчанию буквально клонирует весь репозиторий, включая вещи, на которые вы обычно не хотите тратить свою пропускную способность, например, нефиксированные коммиты. Взято из SO 4811434.
  • это делает git fetch <remote> --tags пропускная способность неэффективна, но не обязательно хранение неэффективно. Вы всегда можете посоветовать своим коллегам не использовать его.
  • вам придется периодически использовать git gc трюк, чтобы очистить ваш репозиторий от любых файлов, которые вы больше не хотите.
  • это не так эффективно, как bup или git-bigfiles. Но это соответственно больше подходит для того, что вы пытаетесь сделать, и больше готово. Вы, вероятно, столкнетесь с проблемами с сотнями тысяч небольших файлов или с файлами размером в гигабайты, но читайте дальше для обходных путей.

Добавление бинарных файлов

Прежде чем начать, убедитесь, что вы зафиксировали все свои изменения, ваше рабочее дерево обновлено, и в вашем индексе нет никаких незафиксированных изменений. Это может быть хорошей идеей - перенести все ваши локальные филиалы на удаленный компьютер (github и т. Д.) На случай, если произойдет какая-либо катастрофа.

  1. Создать новую сиротскую ветку. git checkout --orphan binaryStuff сделает свое дело. Это создает ветвь, которая полностью отключена от любой другой ветки, и первый коммит, который вы сделаете в этой ветке, не будет иметь родителя, что сделает его корневым.
  2. Очистите свой индекс, используя git rm --cached * .gitignore,
  3. Сделайте глубокий вдох и удалите все рабочее дерево, используя rm -fr * .gitignore, внутренний .git каталог останется нетронутым, потому что * подстановочный знак не соответствует.
  4. Скопируйте в свой VeryBigBinary.exe или в свой каталог VeryHeavyDirectory/.
  5. Добавьте это && зафиксируйте это.
  6. Теперь это становится сложнее - если вы вставите его в удаленный филиал, все ваши разработчики загрузят его при следующем вызове git fetch засоряя их связь. Вы можете избежать этого, нажав метку вместо ветки. Это все еще может повлиять на пропускную способность вашего коллеги и хранилище файловой системы, если они имеют привычку печатать git fetch <remote> --tags, но читайте дальше для обходного пути. Идти вперед и git tag 1.0.0bin
  7. Нажмите свой тег сироты git push <remote> 1.0.0bin,
  8. Просто так, что вы никогда не нажмете свою бинарную ветку случайно, вы можете удалить ее git branch -D binaryStuff, Ваш коммит не будет помечен для сборки мусора, потому что на него указывает потерянный тег 1.0.0bin достаточно, чтобы сохранить его в живых.

Проверка двоичного файла

  1. Как я (или мои коллеги) извлекаю VeryBigBinary.exe в текущее рабочее дерево? Если ваша текущая рабочая ветка, например, master, вы можете просто git checkout 1.0.0bin -- VeryBigBinary.exe,
  2. Это не удастся, если у вас нет тега-сироты 1.0.0bin скачал, в этом случае вам придется git fetch <remote> 1.0.0bin заранее.
  3. Вы можете добавить VeryBigBinary.exe в твой хозяин .gitignore, так что никто в вашей команде случайно не загрязнит основную историю проекта бинарным.

Полное удаление двоичного файла

Если вы решите полностью удалить VeryBigBinary.exe из вашего локального хранилища, удаленного хранилища и хранилищ вашего коллеги, вы можете просто:

  1. Удалить потерянный тег на пульте git push <remote> :refs/tags/1.0.0bin
  2. Удалить потерянный тег локально (удаляет все остальные теги, на которые нет ссылок) git tag -l | xargs git tag -d && git fetch --tags, Взято из SO 1841341 с небольшой модификацией.
  3. Используйте хитрость git gc, чтобы удалить ваш теперь не имеющий ссылки коммит локально. git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@", Это также удалит все другие не связанные ссылки. Взято из SO 1904860
  4. Если возможно, повторите трюк с git gc на пульте. Это возможно, если вы самостоятельно размещаете свой репозиторий, и это может быть невозможно с некоторыми провайдерами git, такими как github или в некоторых корпоративных средах. Если вы пользуетесь хостингом у провайдера, который не предоставляет доступ по ssh к удаленному, просто оставьте его. Вполне возможно, что инфраструктура вашего провайдера очистит вашу ссылку без привязки в свое приятное время. Если вы находитесь в корпоративной среде, вы можете посоветовать своим ИТ-специалистам запускать мусорное задание cron, собирая пульт один раз в неделю или около того. Независимо от того, влияют они или нет, это не повлияет на вашу команду с точки зрения пропускной способности и хранилища, если вы советуете своим коллегам всегда git clone -b master --single-branch <url> вместо git clone,
  5. Всем вашим коллегам, которые хотят избавиться от устаревших тегов-сирот, нужно только применить шаги 2-3.
  6. Затем вы можете повторить шаги 1-8 из Добавление двоичных файлов, чтобы создать новый потерянный тег 2.0.0bin, Если вы беспокоитесь о том, что ваши коллеги печатают git fetch <remote> --tags Вы можете назвать это снова 1.0.0bin, Это позволит убедиться, что в следующий раз они извлекут все теги старого 1.0.0bin не будет иметь ссылки и помечен для последующей сборки мусора (с помощью шага 3). Когда вы пытаетесь перезаписать тег на пульте, вы должны использовать -f как это: git push -f <remote> <tagname>

Послесловие

  • OTABS не касается вашего мастера или любых других исходных кодов / веток разработки. Хеши коммитов, вся история и небольшой размер этих веток не затрагиваются. Если вы уже раздули историю исходного кода с помощью двоичных файлов, вам придется очистить ее как отдельную часть работы. Этот скрипт может быть полезен.

  • Подтвердил работу на Windows с помощью git-bash.

  • Рекомендуется применять набор стандартных трюков, чтобы сделать хранение бинарных файлов более эффективным. Частый запуск git gc (без каких-либо дополнительных аргументов) заставляет git оптимизировать базовое хранилище ваших файлов с помощью двоичных дельт. Однако, если ваши файлы вряд ли останутся похожими на коммит, вы можете полностью отключить бинарные дельты. Кроме того, поскольку нет смысла сжимать уже сжатые или зашифрованные файлы, такие как.zip,.jpg или.crypt, git позволяет отключить сжатие основного хранилища. К сожалению, это параметр "все или ничего", влияющий и на ваш исходный код.

  • Возможно, вы захотите составить сценарий части OTABS, чтобы обеспечить более быстрое использование. В частности, сценарии 2-3 из полного удаления двоичных файлов в update git hook может дать убедительную, но, возможно, опасную семантику для git fetch ("получить и удалить все, что устарело").

  • Возможно, вы захотите пропустить шаг 4 " Полное удаление двоичных файлов", чтобы сохранить полную историю всех двоичных изменений на удаленном компьютере за счет увеличения объема центрального хранилища. Локальные хранилища со временем останутся сухими.

  • В мире Java можно комбинировать это решение с maven --offline создать воспроизводимую автономную сборку, хранящуюся полностью в вашем контроле версий (это проще с maven, чем с gradle). В мире Голанга возможно использовать это решение для управления GOPATH вместо go get, В мире Python это можно комбинировать с virtualenv для создания автономной среды разработки, не полагаясь на серверы PyPi для каждой сборки с нуля.

  • Если ваши двоичные файлы меняются очень часто, например, артефакты сборки, неплохо было бы написать сценарий решения, в котором 5 последних версий артефактов хранятся в потерянных тегах. monday_bin, tuesday_bin,..., friday_bin, а также сиротский тег для каждого выпуска 1.7.8bin2.0.0bin и т. д. Вы можете вращать weekday_bin и удаляйте старые двоичные файлы ежедневно. Таким образом, вы получаете лучшее из двух миров: вы сохраняете всю историю вашего исходного кода, но только соответствующую историю ваших бинарных зависимостей. Также очень легко получить двоичные файлы для данного тега, не получая весь исходный код со всей его историей: git init && git remote add <name> <url> && git fetch <name> <tag> должен сделать это для вас.

На мой взгляд, если вы, вероятно, будете часто изменять эти большие файлы, или если вы собираетесь сделать много git clone или же git checkout, тогда вам следует серьезно подумать об использовании другого Git-репозитория (или, возможно, другого способа доступа к этим файлам).

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

SVN, кажется, обрабатывает двоичные дельты более эффективно, чем Git.

Я должен был выбрать систему управления версиями для документации (файлы JPEG, файлы PDF и файлы.odt). Я только что протестировал добавление файла JPEG и поворот его на 90 градусов четыре раза (чтобы проверить эффективность двоичных дельт). Репозиторий Git вырос на 400%. Репозиторий SVN вырос только на 11%.

Похоже, что SVN намного эффективнее с двоичными файлами.

Поэтому я выбрал Git для исходного кода и SVN для бинарных файлов, таких как документация.

git clone --filterиз Git 2.19 + мелкие клоны

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

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

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

Существует даже уже --filter=blob:limit<size> что позволяет ограничить максимальный размер капли для выборки.

Я привел минимальный подробный пример того, как выглядит эта функция: Как мне клонировать только подкаталог репозитория Git?

Я ищу мнения о том, как обрабатывать большие двоичные файлы, от которых зависит мой исходный код (веб-приложение). Что вы думаете об этом?

Лично я столкнулся с ошибками синхронизации с Git с некоторыми из моих облачных хостов, когда двоичные данные моих веб-приложений оказались выше отметки 3 ГБ. В то время я рассматривал BFT Repo Cleaner, но это было похоже на взлом. С тех пор я начал просто хранить файлы вне сферы действия Git, вместо этого используя специальные инструменты, такие как Amazon S3, для управления файлами, управления версиями и резервного копирования.

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

Да. Уго темы в первую очередь управляются таким образом. Это немного круто, но это делает работу.


Мое предложение состоит в том, чтобы выбрать правильный инструмент для работы. Если это для компании, и вы управляете своей кодовой линией на GitHub, заплатите деньги и используйте Git-LFS. В противном случае вы могли бы изучить более креативные варианты, такие как децентрализованное, зашифрованное хранилище файлов с помощью блокчейна.

Дополнительные опции для рассмотрения включают Minio и s3cmd.

Git LFS — это ответ

      # Init LFS
git lfs install
git lfs track "large_file_pattern"

# Then follow regular git workflow
git add large_file
git commit -m "Init a very large file"
git push origin HEAD

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

Для получения дополнительной информации: https://git-lfs.github.com/

Посмотрите на https://camlistore.org/. На самом деле он не основан на Git, но я считаю его более подходящим для того, что вы должны делать.

Другие вопросы по тегам