Git с большими файлами

ситуация

у меня есть два сервера, производство и разработка. На рабочем сервере есть два приложения и несколько (6) баз данных (MySQL), которые мне нужно распространить разработчикам для тестирования. Все исходные коды хранятся в GitLab на сервере разработки и разработчики работают только с этим сервером и не имеют доступа к рабочему серверу. Когда мы выпускаем приложение, master входит в систему и вытаскивает новую версию из Git. Этот базы данных большие (более 500 м каждая и подсчет), и мне нужно распространять их как можно проще разработчикам для тестирования.

возможные решения

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

    этот был найден не рабочий.

  • Cron на рабочем сервере сохраняет двоичные журналы каждый день и помещает их в ветвь этой базы данных. Итак, в ветке есть файлы с ежедневными изменениями, и разработчик вытаскивает файлы, которых у него нет. Текущий дамп SQL будет отправлен разработчику другим способом. И когда размер репозитория станет слишком большим, мы отправим полный дамп разработчикам и очистим все данные в репозитории и начнем с начало.

вопросы

  • возможно ли решение?
  • если git нажимает/тянет в / из репозитория, загружает / загружает целые файлы или просто изменяет их (т. е. добавляет новые строки или редактирует текущие)?
  • может ли Git управлять такими большими файлами? нет.
  • Как установить, сколько ревизий сохраняется в репозитории? не имеет значения с новым решение.
  • есть ли лучшее решение? Я не хочу заставлять разработчиков загружать такие большие файлы через FTP или что-то подобное.

6 ответов


rsync может быть хорошим вариантом для эффективного обновления разработчиками копий баз данных.

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

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

rsync-стандартная часть большинства дистрибутивов linux, Если вам это нужно в windows, доступен упакованный порт:http://itefix.no/cwrsync/

чтобы передать базы данных разработчику, вы можете использовать команду, подобную:

rsync -avz path/to/database(s) HOST:/folder

или разработчики могут вытащить базы данных, которые им нужны:

rsync -avz DATABASE_HOST:/path/to/database(s) path/where/developer/wants/it

обновление 2017:

Microsoft вносит свой вклад в Microsoft / GVFS: виртуальная файловая система Git, которая позволяет git обрабатывать"крупнейшее РЕПО на планете"
(т. е.: база кода Windows, которая составляет примерно 3,5 м файлов и, при регистрации в репозитории Git, приводит к РЕПО около 300 ГБ и производит 1,760 ежедневных "лабораторных сборок" через 440 филиалов в дополнение к тысячам проверки запроса на вытягивание строит)

GVFS виртуализирует файловую систему под вашим репозиторием git, чтобы git и все инструменты видели то, что кажется обычным РЕПО, но GVFS загружает только объекты по мере необходимости.

некоторые части GVFS могут быть переданы вверх по течению (для самого Git).
А пока ... --39-->все новые разработки Windows теперь (август 2017) на Git.


обновление апрель 2015: GitHub предлагает:объявляет Git большое хранилище файлов (LFS)

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

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

посмотреть git-lfs / wiki / учебник:

git lfs track '*.bin'
git add .gitattributes "*.bin"
git commit -m "Track .bin files"

Оригинал ответ:

о каковы ограничения git с большими файлами, вы можете рассмотреть стоп (подробно представлено в GitMinutes #24)

на дизайн bup выделяет три проблемы, которые ограничивают РЕПО git:

  • большие файлы (the xdelta для packfile находится только в памяти, что не хорошо с большими файлы)
  • огромное количество файлов, что означает, один файл на blob и медленный git gc для создания одного файла пакета за раз.
  • огромный packfiles, с индексом packfile неэффективным для извлечения данных из (огромного) packfile.

обработка огромных файлов и xdelta

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

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

то, что bup делает вместо xdelta, мы называем"hashsplitting."
Мы хотели универсальный способ эффективного резервного копирования любой большой файл, который может меняться небольшими способами, без сохранения всего файла каждый время. Мы читаем файл по одному байту за раз, вычисляя скользящую контрольную сумму последних 128 байты.

rollsum кажется, довольно хорошо справляется со своей работой. вы можете найти его в bupsplit.c.
В принципе, он преобразует последние 128 байт в 32-разрядное целое число. Затем мы берем самые низкие 13 бит rollsum, и если они все 1, мы считаем, что это конец куска.
Это происходит в среднем один раз 2^13 = 8192 bytes, так что средний размер блока 8192 байт.
Мы разделяем эти файлы на куски на основе скользящей контрольной суммы.
Затем мы храним каждый кусок отдельно (индексированный его sha1sum) как Git blob.

С hashsplitting, независимо от того, сколько данных вы добавляете, изменяете или удаляете в середине файла, все куски до и после пораженный кусок абсолютно одинаковые.
Все, что имеет значение для hashsplitting алгоритм-это 32-байтовая последовательность "разделитель", и одно изменение может повлиять только на одну последовательность разделителей или байты между двумя последовательностями разделителей.
Как по волшебству, алгоритм hashsplit chunking будет каждый раз кусать ваш файл одинаково, даже не зная, как он его ранее.

следующая проблема менее очевидна: после того, как вы сохраните серию кусков как Git blobs, как вы сохраняете их последовательность? Каждый blob имеет 20-байтовый sha1 идентификатор, что означает, что простой список объектов будет 20/8192 = 0.25% длина файла.
Для файла 200GB это 488 мегабайт только данных последовательности.

мы расширяем алгоритм hashsplit немного дальше, используя то, что мы называем "fanout."Вместо того, чтобы проверять только последние 13 бит контрольной суммы, мы используем дополнительные биты контрольной суммы для получения дополнительных расщеплений.
То, что вы в конечном итоге, является фактическим деревом капель - какие объекты git 'tree' идеально подходят для представлять собой.

обработка огромного количества файлов и git gc

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

в #1 убийца способ добавления новых объектов в репозиторий: он создает один файл на blob. Затем вы позже запустите "git gc" и объедините эти файлы в один файл (используя высокоэффективное сжатие xdelta и игнорируя любые файлы, которые больше не актуальны).

'git gc' медленно, но для репозиториев исходного кода полученное сверхэффективное хранилище (и связанный с ним действительно быстрый доступ к сохраненным файлам) стоит того.

bup не сделать это. Он просто пишет packfiles напрямую.
К счастью, эти packfiles по-прежнему отформатированы git, поэтому git может с радостью получить к ним доступ один раз они написаны.

обработка огромного репозитория (что означает огромное количество огромных packfiles)

Git на самом деле не предназначен для обработки супер-огромных репозиториев.
Большинство репозиториев git достаточно малы, что разумно объединить их все в один packfile, который 'git gc ' обычно делает в конце концов.

проблемная часть больших packfiles-это не сами packfiles - git разработан, чтобы ожидать, что общий размер всех пакетов будет больше, чем доступная память, и как только он сможет справиться с этим, он может обрабатывать практически любой объем данных одинаково эффективно.
проблема заключается в индексах packfile (.idx) файлы.

каждый packfile (*.pack) в git есть связанный idx (*.idx) это отсортированный список хэшей объектов git и смещений файлов.
Если вы ищете конкретный объект на основе его sha1, вы открываете idx, выполняете двоичный поиск, чтобы найти правильный хэш, затем берете связанное смещение файла, ищете это смещение в файле пакета и читаете содержимое объекта.

производительность двоичного поиска о O(log n) С количеством хэшей в пакете, с оптимизированным первым шагом (вы можете прочитать об этом в другом месте), что несколько улучшает его O(log(n)-7).
К сожалению, это ломается немного, когда у вас есть много пачек.

чтобы улучшить производительность такого рода операций, bup вводит midx (произносится как "midix" и сокращенно от "multi-idx") файлы.
Как следует из названия, они индексируют несколько пакетов одновременно.


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

каждое добавляемое вами обновление будет в совокупности добавлять к общему размеру вашего репозитория, что означает, что в будущем ваше git-РЕПО будет занимать все больше и больше времени для клонирования и использования все большего и большего дискового пространства, потому что Git хранит всю историю филиала локально, что означает, что когда кто-то проверяет филиал, им не просто нужно загрузить последнюю версию базы данных; им также придется загрузить все предыдущие версии.

Если вам нужно предоставить большие двоичные файлы, загрузите их на какой-либо сервер отдельно, а затем проверьте текстовый файл с URL-адресом, где разработчик может загрузить большой двоичный файл. FTP на самом деле является одним из лучше options, так как он специально разработан для передачи двоичных файлов, хотя HTTP, вероятно, еще более прост.


вы можете посмотреть на решение, как git-annex, что касается управления (большими) файлами с git, без проверки содержимого файла в git (!)
(Февраль 2015 года: сервис хостинг, как GitLab интегрирует его изначально:
См."поддерживает ли GitLab большие файлы через git-annex или иначе?")

git не управляет большими файлами, как объясняется Янтарь на ответ.

что это не значит, что git не сможет сделать лучше в один прекрасный день.
От эпизод GitMinutes 9 (май 2013, см. Также ниже) С Peff (Джефф Кинг), в 36'10":

(расшифровка)

есть все другие области больших репозиториев, где люди заинтересованы в хранении, вы знаете, 20 или 30 или 40 ГБ, иногда даже репозиториев размером с ТБ, и да, это происходит от наличия большого количества файлов, но многое из этого происходит от имея действительно большие файлы и действительно большие двоичные файлы, которые не так хорошо справляются друг с другом.

это своего рода открытая проблема. Есть несколько решений: git-annex, вероятно, самый зрелый из тех, где они в основном не помещают актив в git, они помещают большой актив на сервер активов и ставят указатель в git.

Я хотел бы сделать что-то подобное, где актив принципиально в git, то есть SHA1 этого объекта является частью SHA1, которая входит в дерево, которая входит в идентификатор фиксации и все эти вещи.
Таким образом, с точки зрения git, он является частью репозитория, но на уровне ниже, на уровне хранения объектов, на уровне ниже концептуальная график истории, где у нас уже есть несколько способов хранения объекта: у нас есть свободные объекты, мы упакованные объекты, Я хотел бы иметь, возможно, новый способ хранения объекта, который это сказать: "у нас его нет, но он доступен сервером активов" или что-то в этом роде.

(Томас Феррис Николайсен) О, круто...

проблема с такими вещами, как git-annex: Как только вы используете их, вы... навсегда запертый в решениях, которые ты принял в то время. Вы знаете, что если вы решите, что oh 200 MB большой, и мы будем хранить на сервере активов, а затем, позже вы решите, aah это должно было быть 300 МБ, ну, не повезло: это закодировано в вашей истории навсегда.
И так сказать принципиально, на уровне git этот объект на репозиторий git, а не какой-то указатель на него, а не какой-то указатель на сервер активов,фактический объект есть, а затем заботиться о тех деталях на низком уровне, на уровне хранения, то это освобождает вас, чтобы сделать много различных решений, и даже изменить ваше решение позже о том, как вы действительно хотите сохранить материал на диске.

не первоочередной проект...


3 года спустя, в апреле 2016 года, Git Минут 40 включает в себя интервью Майкл Хэггерти из GitHub около 31' (спасибо Христианская Couder в интервью).

Он специализировался на справочном бэк-энде довольно долго.
Он цитирует Дэвид ТернерС работой на back-end как самый интересный на данный момент. (См.ток Дэвида"pluggable-backends " ветвь его git / git вилка)

(расшифровка)

Christian Couder (CD): цель состоит в том, чтобы git refs хранились в базе данных, например? Майкл Хаггерти (MH): Да, я вижу это как два интересных аспекта: первый-это просто возможность подключать разные ссылки на исходные данные. Запись ссылки хранятся в файловой системе, как сочетание свободных ссылок и упакованные ссылок.
Свободная ссылка-это один файл на ссылку, а упакованная ссылка-один большой файл, содержащий список многих ссылок.

Так что это хорошая система, особенно для локального использования; поскольку у нее нет реальной проблемы с производительностью для нормальных людей, но у нее есть некоторые проблемы, например, вы не можете хранить рефлоги ссылок после удаления ссылок, потому что могут быть конфликты с новыми ссылками, которые были созданы с похожими именами. Существует также проблема, когда ссылочные имена хранятся в файловой системе, поэтому вы можете иметь ссылки, которые называются похожими, но с разной капитализацией.
Таким образом, это вещи, которые могут быть исправлены, имея другую справочную систему в целом.
И другой аспект серии патчей Дэвида Тернера-это изменение для хранения ссылок в базе данных под названием lmdb, это очень быстрая база данных на основе памяти, которая имеет некоторые преимущества в производительности по сравнению с фоновым файлом.

[следует за другими соображениями вокруг иметь более быструю упаковку, и рекламу заплаты ссылки]


наличие вспомогательного хранилища файлов, на которые ссылается ваш git-спрятанный код, - это то, куда большинство людей идут. git-annex выглядит довольно всеобъемлющим, но многие магазины просто используют репозиторий FTP или HTTP (или S3) для больших файлов, таких как SQL-дампы. Мое предложение состояло бы в том, чтобы связать код в репозитории git с именами файлов во вспомогательном хранилище, заполнив некоторые метаданные - в частности контрольную сумму (возможно, SHA) - в хэш, а также дату.

  • так каждый файл aux получает базовое имя, дату и SHA(для некоторой версии n) sum.
  • если у вас есть дикий оборот файлов, использование только SHA представляет собой крошечную, но реальную угрозу хэш-столкновения, следовательно, включение даты (время эпохи или дата ISO).
  • поместите полученное имя файла в код, так что AUX chunk включен, очень конкретно, по ссылке.
  • структурируйте имена таким образом, чтобы небольшой скрипт можно было легко записать в Git grep все имена файлов aux, чтобы список для любой фиксации тривиален для получения. Это также позволяет старым удаляться в какой-то момент и может быть интегрирована с системой развертывания, чтобы вытащить новые файлы aux на производство без clobbering старых (пока), до активации кода из репозитория git.

Втискивание огромных файлов в git (или большинство репозиториев) оказывает неприятное влияние на производительность git через некоторое время - a git clone действительно не должно занять двадцать минут, например. В то время как использование файлы по ссылке означает, что некоторым разработчикам никогда не придется загружать большие куски вообще (резкий контраст с git clone), поскольку большинство из них имеют отношение только к развернутому коду в производстве. Конечно, ваш пробег может отличаться.


загрузка больших файлов иногда создает проблемы и ошибки. Обычно такое случается. В основном git поддерживает менее 50 МБ файла для загрузки. Для загрузки более 50 МБ файлов в репозиторий Git пользователю необходимо установить другой помощник, который сотрудничает для загрузки большого файла(.mp4,.mp3,.psd) и т.д.

есть несколько основных команд git, которые вы знаете перед загрузкой большого файла в git. это конфигурация для загрузки на GitHub. он должен установить gitlfs.exe

установить его из lfsinstall.exe



тогда вы должны использовать основные команды git вместе с некоторыми другими

git lfs install
git init
git lfs track ".mp4"
git lfs track ".mp3"
git lfs track ".psd"
git add .
git add .gitattributes
git config lfs.https://github.com/something/repo.git/info/lfs.locksverify false 
git commit -m "Add design file"
git push origin master` ones

вы можете найти вы найдете его lfs.https://github.com/something/repo.git/info/lfs.locksverify false как инструкции во пуш если нажать без его использования