Неглубокий и разреженный клон репозитория GIT

У меня есть неглубокий клонированный репозиторий git размером более 1 ГБ. Я использую разреженную проверку необходимых файлов / каталогов.

Как я могу уменьшить клон репозитория до разреженных файлов / каталогов проверки?

Изначально я мог ограничить клонированный репозиторий только разреженной проверкой, отключив проверку при клонировании. Затем настройте разреженную проверку перед выполнением первоначальной проверки. Это ограничило размер репозитория примерно 200 МБ. Намного более управляемый. Однако обновление информации об удаленной ветке в какой-то момент в будущем приведет к включению остальных файлов и каталогов в клон репозитория. Отправка размера клона репо обратно до более 1 ГБ, и я не знаю, как использовать только разреженные файлы и каталоги проверки.

Короче говоря, мне нужен неглубокий И разреженный репозиторий клон. Не только редкая проверка неглубокого клона репо. Полное репо - это пустая трата места, и производительность для определенных задач страдает.

Надеюсь, кто-нибудь поделится решением. Спасибо.


person NOYB    schedule 26.09.2018    source источник
comment
Это полностью реализовано в Git 2.25 (первый квартал 2020 г.): см. Пример в конце моего ответа ниже.   -  person VonC    schedule 20.01.2020


Ответы (1)


Мелкий и редкий означает частичный или узкий.

Частичный клон (или узкий клон) теоретически возможен и был впервые реализован в декабре 2017 года с Git 2.16, как здесь.
Но:

Это дополнительно оптимизировано в Git 2.20 (4 квартал 2018 г.), поскольку в частичном клоне, который будет лениво гидратироваться из исходного репозитория, мы обычно хотим избежать существования этого объекта (локально)? на объектах, которые мы намеренно опускали при создании (частичного / разреженного) клона.
Однако путь кода дерева кэша (который используется для записи объекта дерева из индекса) настаивал на том, что объект существует, даже для путей которые находятся за пределами области частичной проверки.
Код был обновлен, чтобы избежать такой проверки.

См. commit 2f215ff (09 октября 2018 г.) по Джонатан Тан (jhowtan).
(Объединено с помощью Junio ​​C Hamano - gitster - в совершить a08 a>, 19 октября 2018 г.)

cache-tree: пропустить некоторые проверки BLOB-объектов при частичном клонировании

В частичном клоне всякий раз, когда происходит разреженная проверка, проверяется наличие всех больших двоичных объектов в индексе, независимо от того, включены ли они или исключены спецификацией .git/info/sparse-checkout.
Это значительно снижает производительность, поскольку ленивая выборка происходит всякий раз, когда существует проверяется отсутствующий BLOB-объект.


В Git 2.24 (4 квартал 2019 г.) код cache-tree научился менее агрессивно пытаться увидеть, существует ли уже вычисленный им объект дерева в репозитории.

См. commit f981ec1 (3 сентября 2019 г.) от Джонатан Тан (jhowtan).
(Объединено с помощью Junio ​​C Hamano - gitster - в совершить / a>, 07 окт.2019 г.)

cache-tree: не извлекайте предварительное дерево ленивым способом

Структура данных cache-tree используется для ускорения сравнения между HEAD и индексом, а когда индекс обновляется выбором вишни (например), древовидный объект, который будет представлять пути в index в каталоге создается в ядре, чтобы увидеть, существует ли такой объект дерева уже в хранилище объектов.

Когда был введен механизм lazy-fetch, мы преобразовали его: существует ли дерево? проверьте, если это не так, и если мы лениво клонировали, посмотрите, не вызвал ли его по ошибке удаленный компьютер.
Так как весь смысл этой проверки состоит в том, чтобы восстановить дерево кэша путем записи уже существующего объекта дерева в зависимости от обстоятельств , мы даже не должны пытаться получить его с пульта.

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


В Git 2.25 (первый квартал 2020 г.) git fetch codepath имел большой переключатель «не лениво извлекать отсутствующие объекты, когда я спрашиваю, существует ли что-то».

Это было исправлено пометкой "Существует ли эта вещь?" звонит, если нет, пожалуйста, не лениво снимайте флаг.

См. фиксацию 603960b, совершить e362fad (13 ноября 2019 г.) и совершить 6462d5e (5 ноября 2019 г.), автор Джонатан Тан (jhowtan). < br /> (объединено Junio ​​C Hamano - gitster - в commit fce9e83, 1 декабря 2019 г.)

clone: удалить fetch_if_missing=0

Подписано: Джонатан Тан

Коммит 6462d5eb9a (выборка: удалить fetch_if_missing=0", 2019-11-08) попытался устранить необходимость для fetch_if_missing=0 из механизма выборки, поэтому вполне вероятно попытаться удалить fetch_if_missing=0 и из клона. Но это обнаруживает ошибку - когда сервер не отправляет объект, на который прямо указывает ссылка, это должна быть ошибка, а не триггер для ленивой выборки. (Этот случай в механизме выборки был рассмотрен тестом с использованием git clone, а не git fetch, поэтому вышеупомянутая фиксация не обнаружила ошибку.)

Ошибка может быть исправлена ​​путем подавления ленивой выборки во время проверки подключения. Исправьте эту ошибку и удалите fetch_if_missing из клона.

И:

promisor-remote: удалить fetch_if_missing=0

Подписано: Джонатан Тан

Коммит 6462d5eb9a (выборка: удалить fetch_if_missing=0", 2019-11-08) попытался устранить необходимость для fetch_if_missing=0 из механизма выборки, поэтому вполне вероятно попытаться удалить fetch_if_missing=0 из механизма ленивой выборки также в promisor-remote.

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

Таким образом, когда переговорщик не используется во время выборки, воздержитесь от его инициализации. Затем удалите fetch_if_missing из promisor-remote.


Узнайте больше с помощью Уменьшите размер своего монорепозитория с помощью разреженной проверки из Деррика Столи

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

$ git clone --filter=blob:none --no-checkout https://github.com/derrickstolee/sparse-checkout-example
Cloning into 'sparse-checkout-example'...
Receiving objects: 100% (373/373), 75.98 KiB | 2.71 MiB/s, done.
Resolving deltas: 100% (23/23), done.
 
$ cd sparse-checkout-example/
 
$ git sparse-checkout init --cone
Receiving objects: 100% (3/3), 1.41 KiB | 1.41 MiB/s, done.
 
$ git sparse-checkout set client/android
Receiving objects: 100% (26/26), 985.91 KiB | 5.76 MiB/s, done.

До Git 2.25.1 (февраль 2020 г.) has_object_file() сказал, что no получил объект, зарегистрированный в системе через pretend_object_file(), что сделало его несовместимым с read_object_file(), в результате чего ленивая выборка пыталась получить пустое дерево с пультов Promisor.

См. обсуждение.

Я пытался воспроизвести это с помощью

empty_tree=$(git mktree </dev/null)
git init --bare x
git clone --filter=blob:none file://$(pwd)/x y
cd y
echo hi >README
git add README
git commit -m 'nonempty tree'
GIT_TRACE=1 git diff-tree "$empty_tree" HEAD

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

См. фиксацию 9c8a294 (2 января 2020 г.) по Джонатан Тан (jhowtan).
(Объединено с помощью Junio ​​C Hamano - gitster - в sha1-file: удалить OBJECT_INFO_SKIP_CACHED

Подписано: Джонатан Тан

В частичном клоне, если пользователь предоставляет хеш пустого дерева (git mktree </dev/null - для SHA-1 это 4b825d ...) для команды, которая требует, чтобы этот объект был проанализирован, например:

git diff-tree 4b825d <a non-empty tree>

тогда Git будет лениво извлекать пустое дерево без необходимости, потому что синтаксический анализ этого объекта вызывает repo_has_object_file(), что не является частным случаем пустого дерева.

Вместо этого научите repo_has_object_file() обращаться к find_cached_object() (который обрабатывает пустое дерево), таким образом приведя его в соответствие с остальными object-store-accessing функциями.
Стоимость состоит в том, что repo_has_object_file() теперь потребуется oideq при каждом вызове, но это тривиально по сравнению с поиском в файловой системе или поиском по индексу пакетов, необходимым в любом случае. (И если find_cached_object() нужно сделать больше из-за предыдущих вызовов pretend_object_file(), тем более важно быть последовательным в том, представляем ли мы кэшированные объекты.)

Историческая справка: функция, теперь известная как repo_read_object_file(), была обучена пустому дереву в 346245a1bb. (жестко закодируйте объект пустого дерева, 13.02.2008, Git v1.5.5-rc0 - merge), а функции, теперь известной как oid_object_info(), было обучено пустое дерево в c4d9986f5f (sha1_object_info: изучите и cached_object магазин, 07.02.2011, Git v1.7.4.1).

repo_has_object_file() никогда не обновлялся, возможно из-за недосмотра.
Флаг OBJECT_INFO_SKIP_CACHED,, представленный позже в df9dd4af / a> (sha1_file: научить sha1_object_info_extended больше флагов, 2017-06-26, Git v2.14.0-rc0) и используется в e83e71c5e1 (sha1_file: refactor has_sha1_file_with_flags, 2017-06-26, Git v2.14.0-rc0) был введен для сохранения этой разницы в обработке пустых деревьев, но теперь ее можно удалить.


Git 2.25.1 также предупредит программистов о pretend_object_file(), который позволяет коду ориентировочно использовать внутренние объекты.

См. фиксацию 60440d7 (4 января 2020 г.) по Джонатан Нидер (artagnon).
(Объединено с помощью Junio ​​C Hamano - gitster - в фиксации b486d2 a>, 12 фев 2020 г.)

sha1-file: документ, как использовать pretend_object_file

Вдохновленный: Джунио Си Хамано
Подписано: Джонатан Нидер

Как и альтернатива в памяти, pretend_object_file содержит ловушку для неосторожных: неосторожные вызывающие лица могут использовать ее для создания ссылок на объект, которого нет в хранилище объектов на диске .

Добавьте комментарий, описывающий, как использовать функцию, не рискуя такими проблемами.

Виноват единственный текущий вызывающий объект, который использует pretend_object_file для создания фиксации в памяти, представляющей состояние рабочего дерева. Замечено во время обсуждения того, как безопасно использовать эту функцию в таких операциях, как git merge, которые, в отличие от blame, не доступны только для чтения.

Итак, сейчас:

/*
 * Add an object file to the in-memory object store, without writing it
 * to disk.
 *
 * Callers are responsible for calling write_object_file to record the
 * object in persistent storage before writing any other new objects
 * that reference it.
 */
int pretend_object_file(void *, unsigned long, enum object_type,
            struct object_id *oid);

Git 2.25.1 (февраль 2020 г.) включает Futureproofing, чтобы убедиться, что тест не зависит от текущих деталей реализации.

См. фиксацию b54128b (13 января 2020 г.) по Джонатан Тан (jhowtan).
(Объединено с помощью Junio ​​C Hamano - gitster - в фиксации 3f7553a a>, 12 фев 2020 г.)

t5616: сделать устойчивое изменение базы дельты

Подписано: Джонатан Тан

Фиксация 6462d5eb9a (выборка: удалить fetch_if_missing=0", 2019-11-08) содержит тест, который полагается о необходимости лениво получать дельта-базу большого двоичного объекта, но предполагает, что извлекаемое дерево (как часть теста) отправляется как объект без дельта.
Это предположение может не выполняться в будущем; например, изменение длины хэша объекта может привести к тому, что дерево будет отправлено как дельта.

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


Git 2.25.2 (март 2020 г.) исправляет ошибку, обнаруженную недавним изменением, и делает протокол v2 по умолчанию.

См. фиксацию 3e96c66, commit d0badf8 (21 февраля 2020 г.) от (derrickstolee).
(Объединено Junio ​​C Hamano - gitster - в commit 444cff6, 2 марта 2020 г.)

partial-clone: избегайте выборки при поиске объектов

Подписано: Деррик Столи

Во время тестирования частичного клона я заметил странное поведение. Я тестировал способ запуска «git init», затем вручную настраивал пульт для частичного клонирования, а затем запускал «git fetch».
Удивительно, я видел, как процесс «git fetch» начал запрашивать у сервера несколько раундов загрузок pack-файлов! Еще немного изменив ситуацию, я обнаружил, что могу привести к зависанию пульта дистанционного управления с ошибкой.

Добавьте два теста, которые демонстрируют эти две проблемы.

В первом тесте мы обнаружили, что при выборке с помощью фильтров BLOB-объектов из репозитория, в котором ранее не было тегов, тег '_ 78_ origin 'Команда не работает, потому что сервер отправляет несколько спецификаций фильтров, которые нельзя объединить. Это происходит только при использовании протокола v2.

Во втором тесте мы видим, что запрос "git fetch origin" с несколькими обновлениями ссылок приводит к многократной загрузке файла пакета.
Это должно быть из-за того, что Git пытается исправить объекты, указанные в ссылках. Что делает этот вопрос особенно неприятным, так это то, что он проходит через метод do_oid_object_info_extended(), поэтому в согласовании нет ничего лишнего.
Это заставляет удаленный компьютер отправлять каждую достижимую фиксацию и дерево из каждой новой ссылки, предоставляя квадратичный объем данных перечислить! Этот тест будет исправлен, если мы вернем 6462d5eb9a (получить: удалить fetch_if_missing=0, 2019-11-05 , Git v2.25.0-rc0), но этот откат вызывает другие сбои теста.
Настоящее исправление потребует большей осторожности.

Исправить:

При использовании частичного клонирования find_non_local_tags() в builtin/fetch.c проверяет каждый удаленный тег чтобы увидеть, существует ли его объект локально. Не ожидается, что объект существует локально, но эта функция, тем не менее, запускает ленивую выборку, если объект не существует. Это может быть очень дорого при запросе фиксации, поскольку мы полностью удаляемся из контекста несуществующего объекта и, таким образом, не предоставляем никаких преимуществ в запросе.

6462d5eb9a (fetch: удалить fetch_if_missing=0, 2019-11-05, Git v2.25.0-rc v2.25.0-rc ,, Git v2.25.0-rc0) удалила глобальную переменную, которая препятствовала этим выборкам, в пользу битового флага. Однако некоторые проверки существования объекта не обновлялись для использования этого флага.

Обновите find_non_local_tags(), чтобы использовать OBJECT_INFO_SKIP_FETCH_OBJECT в дополнение к OBJECT_INFO_QUICK.
Параметр _QUICK предотвращает только повторное представление структур пакетных файлов. Нам нужно быть очень осторожными с предоставлением _SKIP_FETCH_OBJECT, когда мы ожидаем, что объект не существует из-за обновленных ссылок.

Это решает проблему неработающего теста в t5616-partial-clone.sh.


Логика автоматического отслеживания тегов в git clone --single-branch не была осторожна, чтобы избежать ленивой выборки ненужных тегов, что было исправлено в Git 2.27 (второй квартал 2020 г.),

См. commit 167a575 (01 апреля 2020 г.) по Джефф Кинг (peff).
(Объединено Junio ​​C Hamano - gitster - в совершить 3e a>, 22 апр 2020 г.)

clone: используйте быстрый поиск, следуя тегам

Подписано: Джефф Кинг

При клонировании с --single-branch мы реализуем обычное для git fetch поведение следования за тегами, захватывая любые объекты тегов, которые указывают на объекты, которые есть у нас локально.

Однако, когда мы являемся частичным клоном, наша has_object_file() проверка будет выполнять ленивую выборку каждого тега.

Это не только сводит на нет цель --single-branch, но и делает это невероятно медленно, потенциально вызывая новую выборку для каждого тега.
Это еще хуже для мелкого клона, что подразумевает --single-branch, потому что даже теги, которые являются надмножествами друг друга, будут извлекаться индивидуально.

Мы можем исправить это, передав OBJECT_INFO_SKIP_FETCH_OBJECT вызову, что и делает git fetch в этом кейс.

Точно так же давайте включим OBJECT_INFO_QUICK,, поскольку это то, что делает git fetch.
Обоснование таково. обсуждается в 5827a03545 (выборка: используйте quick has_sha1_file для отслеживания тегов, 2016-10-13 , Git v2.10.2), но здесь компромисс будет применяться даже в большей степени, потому что клон вряд ли будет конкурировать с другим процессом, перепаковывающим наш недавно созданный репозиторий.

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


До Git 2.27 (второй квартал 2020 г.) обслуживание клиента git fetch по протоколам git:// и ssh:// с использованием протокола on-wire версии 2 было ошибочным на стороне сервера, когда клиенту нужно было сделать последующий запрос, например, автоматическое отслеживание тегов.

См. commit 08450ef (8 мая 2020 г.) по Christian Couder (chriscool).
(Объединено Джунио С. Хамано - gitster - в upload-pack: очистить filter_options для каждой команды получения v2

Помощник: Деррик Столи
Помощник: Джефф Кинг
Помощник: Тейлор Блау
Подписано: Кристиан Кудер

Из-за модели запроса / ответа протокола v2 функция upload_pack_v2() иногда вызывается дважды в одном и том же процессе, в то время как 'struct list_objects_filter_options filter_options' была объявлена ​​как статическая в начале '_ 117_ '.

Это привело к тому, что проверка в list_objects_filter_die_if_populated(), который вызывается process_args(), завершилась ошибкой при втором вызове upload_pack_v2(), поскольку filter_options уже был заполнен в первый раз.

Чтобы исправить это, filter_options больше не статичен. Теперь он принадлежит напрямую upload_pack(). Теперь он также является частью struct upload_pack_data, так что он косвенно принадлежит upload_pack_v2().

В долгосрочной перспективе цель состоит в том, чтобы upload_pack() также использовала 'struct upload_pack_data', поэтому добавление filter_options к этой структуре имеет больше смысла, чем прямое владение ею upload_pack_v2().

Это исправляет первую из 2 ошибок, задокументированных d0badf8797 (partial-clone: демонстрация ошибок в частичной fetch, 2020-02-21, Git v2.26.0-rc0 - указано слияние в пакете № 8).


В Git 2.29 (4 квартал 2020 г.) механизм pretend-object проверяет, существует ли уже данный объект в хранилище объектов, прежде чем принять решение о хранении данных в ядре, но проверка могла бы вызвать ленивую выборку такого объекта с удаленного сервера промиссора.

См. фиксацию a64d2aa (21 июля 2020 г.) по Джонатан Тан (jhowtan).
(Объединено пользователем Junio ​​C Hamano - gitster - в совершить 5b133 a>, 4 августа 2020 г.)

sha1-file: сделать pretend_object_file() без предварительной выборки

Подписано: Джонатан Тан

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

Это было замечено на $DAYJOB, когда blame запускался с файлом, который имел незафиксированные изменения.

person VonC    schedule 26.09.2018
comment
Не вижу никакой документации по re: частичному узкому или параметру --filter. git версия 2.19.0.windows.1 - person NOYB; 27.09.2018
comment
@NOYB Вы увидите это в github.com/git/git/commit/. - person VonC; 27.09.2018
comment
Видимо частичное клонирование (--filter) не поддерживается github. предупреждение: фильтрация не распознается сервером, игнорирование. Все репо на 1,4 ГБ все еще клонировано. git clone --no-checkout --filter = blob: none github.com/freebsd/freebsd-ports < / а> pc1 - person NOYB; 27.09.2018
comment
@NOYB Точно: это все еще развертывается и еще не поддерживается основными службами хостинга репозиториев Git. Вам нужно будет запустить свой собственный сервер с последней версией Git в качестве зеркала, чтобы клонировать / выталкивать / извлекать из этого зеркала. - person VonC; 27.09.2018
comment
Спасибо, что рассказали мне о предстоящей возможности частичного клонирования. Как только он будет поддержан github, это станет очень полезной функцией. Но на данный момент необходимость в локальном полном клоне не принесла бы мне смысла. Есть идеи относительно приблизительных вероятных сроков поддержки github? Спасибо - person NOYB; 28.09.2018