Spec-Zone.ru › Git

git-fast-import

Название

git-fast-import — серверная часть для средств быстрого импорта данных в Git

Краткое описание

frontend | git fast-import [<options>]

Описание

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

fast-import считывает смешанный поток команд и данных из стандартного ввода и напрямую записывает один или несколько pack-файлов в текущий репозиторий. При получении EOF на стандартном вводе fast-import записывает обновлённые ссылки веток и тегов, полностью обновляя текущий репозиторий новыми импортированными данными.

Серверная часть fast-import может импортировать данные как в пустой репозиторий (уже инициализированный с помощью git init), так и постепенно обновлять уже заполненный репозиторий. Поддержка инкрементального импорта из конкретного внешнего источника зависит от используемой фронтенд-программы.

Параметры

--force

Принудительно обновлять изменённые существующие ветки, даже если это приведёт к потере коммитов (так как новый коммит не содержит старый).

--quiet

Отключить вывод статистики, отображаемой параметром --stats, чтобы fast-import обычно не выводил сообщений при успешном выполнении. Однако если поток импорта содержит директивы, предназначенные для вывода сообщений пользователю (например, директивы progress), соответствующие сообщения всё равно будут показаны.

--stats

Вывести основную статистику об объектах, созданных fast-import, pack-файлах, в которых они хранятся, и памяти, использованной fast-import во время выполнения. Сейчас этот вывод включён по умолчанию, но его можно отключить с помощью --quiet.

--allow-unsafe-features

Многие параметры командной строки можно передавать непосредственно в потоке fast-import с помощью команд feature или option. Однако некоторые из этих параметров небезопасны (например, разрешение fast-import обращаться к файловой системе за пределами репозитория). По умолчанию эти параметры отключены, но их можно разрешить, указав этот параметр в командной строке. В настоящее время это касается только команд feature export-marks, import-marks и import-marks-if-exists.

Включайте этот параметр, только если доверяете программе, создающей поток fast-import! Этот параметр автоматически включается для удалённых помощников, использующих возможность import, поскольку им уже доверено выполнение собственного кода.

--signed-tags=<mode>

Указать, как обрабатывать подписанные теги. Работает так же, как параметр --signed-commits=<mode> ниже. Как и для подписанных коммитов, режим по умолчанию — verbatim.

--signed-commits=<mode>

Указать, как обрабатывать подписанные коммиты. Поддерживаются следующие значения <mode>:

  • verbatim, значение по умолчанию: подписи коммитов импортируются без вывода сообщений.

  • warn-verbatim: подписи импортируются, но выводится предупреждение.

  • abort: программа завершится с ошибкой при обнаружении подписанного коммита.

  • strip: подписи коммитов будут удалены без вывода сообщений.

  • warn-strip: подписи коммитов будут удалены, и будет выведено предупреждение.

  • strip-if-invalid: подписи проверяются, а недействительные удаляются с выводом предупреждения. Проверка выполняется так же, как в git-verify-commit[1].

  • sign-if-invalid[=<keyid>], подобно strip-if-invalid, проверяет подписи коммитов и заменяет недействительные новыми. Действительные подписи остаются без изменений. Если указан <keyid>, для подписи используется этот ключ; в противном случае используется настроенный ключ подписи по умолчанию.

  • abort-if-invalid: программа завершится с ошибкой при обнаружении подписанного коммита, подпись которого невозможно проверить.

Параметры для фронтендов

--cat-blob-fd=<fd>

Записывать ответы на запросы get-mark, cat-blob и ls в файловый дескриптор <fd> вместо stdout. Позволяет отделить вывод progress, предназначенный конечному пользователю, от остального вывода.

--date-format=<fmt>

Указать тип дат, которые фронтенд будет передавать fast-import в командах author, committer и tagger. Подробные сведения о поддерживаемых форматах и их синтаксисе см. в разделе «Форматы дат» ниже.

--done

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

Расположение файлов меток

--export-marks=<file>

По завершении сохранить внутреннюю таблицу меток в <file>. Метки записываются по одной в строке в формате :markid SHA-1. Фронтенды могут использовать этот файл для проверки импорта после его завершения или для сохранения таблицы меток между инкрементальными запусками. Поскольку <file> открывается и очищается только при контрольной точке (или завершении), тот же путь можно безопасно передать и параметру --import-marks.

--import-marks=<file>

Перед обработкой любых входных данных загрузить метки, указанные в <file>. Входной файл должен существовать, быть доступным для чтения и иметь тот же формат, что и файл, создаваемый параметром --export-marks. Можно указать несколько параметров, чтобы импортировать несколько наборов меток. Если одной метке соответствуют разные значения, используется значение из последнего файла.

--import-marks-if-exists=<file>

Работает как --import-marks, но вместо ошибки при отсутствии файла он молча пропускается.

--relative-marks
--no-relative-marks

После указания --relative-marks пути, заданные с помощью --import-marks= и --export-marks=, считаются относительно внутреннего каталога текущего репозитория. В git-fast-import это означает, что пути задаются относительно каталога .git/info/fast-import. Однако другие средства импорта могут использовать другое расположение.

Относительные и абсолютные метки можно комбинировать, чередуя параметры --(no-)-relative-marks с параметрами --(import|export)-marks=.

Преобразование подмодулей

--rewrite-submodules-from=<name>:<file>
--rewrite-submodules-to=<name>:<file>

Переписать идентификаторы объектов для подмодуля с именем <name>: заменить значения из исходного файла <file> значениями из целевого файла <file>. Исходные метки должны быть созданы командой git fast-export, а целевые — командой git fast-import при импорте того же подмодуля.

<name> может быть любой произвольной строкой без двоеточия, но для указания соответствующих меток в обоих параметрах необходимо использовать одно и то же значение. Можно указать несколько подмодулей с разными значениями <name>. Эти параметры необходимо указывать парами, иначе произойдёт ошибка.

Эти параметры особенно полезны при преобразовании репозитория с одного алгоритма хеширования на другой: без них fast-import завершится с ошибкой при обнаружении подмодуля, поскольку не сможет записать идентификатор объекта с использованием нового алгоритма хеширования.

Настройка производительности и сжатия

--active-branches=<n>

Максимальное количество веток, которые могут одновременно оставаться активными. Подробные сведения см. ниже в разделе «Использование памяти». Значение по умолчанию — 5.

--big-file-threshold=<n>

Максимальный размер blob-объекта в байтах, для которого fast-import будет пытаться создать дельту. Значение по умолчанию — 512m (512 МиБ). При ограниченном объёме памяти некоторые средства импорта могут предпочесть уменьшить это значение.

--depth=<n>

Максимальная глубина дельты для blob-объектов и деревьев. Значение по умолчанию — 50.

--export-pack-edges=<file>

После создания pack-файла вывести в <file> строку с именем pack-файла и последним коммитом каждой ветки, записанным в этот pack-файл. Эта информация может пригодиться после импорта проектов, общий набор объектов которых превышает ограничение pack-файла в 4 ГиБ: эти коммиты можно использовать как граничные точки при вызовах git pack-objects.

--max-pack-size=<n>

Максимальный размер каждого выходного pack-файла. По умолчанию ограничение отсутствует.

fastimport.unpackLimit

См. git-config[1]

Производительность

Архитектура fast-import позволяет импортировать крупные проекты с минимальными затратами памяти и времени обработки. Если фронтенд успевает за fast-import и передаёт ему непрерывный поток данных, импорт проектов с историей длиной более 10 лет и более чем 100 000 отдельных коммитов обычно занимает всего 1–2 часа даже на довольно скромном оборудовании (стоимостью около 2 000 долларов США в 2007 году).

Большинство узких мест связано с доступом к данным внешнего источника (источник просто не может извлекать ревизии достаточно быстро) или с дисковым вводом-выводом (fast-import записывает данные настолько быстро, насколько позволяет диск). Импорт выполняется быстрее, если исходные данные хранятся на другом диске, нежели целевой репозиторий Git (за счёт меньшей нагрузки на ввод-вывод).

Затраты на разработку

Типичный фронтенд для fast-import обычно занимает около 200 строк кода на Perl/Python/Ruby. Большинство разработчиков смогли создать работающие средства импорта всего за пару часов, даже если прежде они не работали с fast-import, а иногда и с Git. Это идеальный вариант, поскольку большинство средств преобразования — одноразовые (их используют один раз и больше к ним не возвращаются).

Параллельная работа

Как и git push или git fetch, импорт с помощью fast-import безопасно выполнять параллельно с вызовами git repack -a -d или git gc, а также с любыми другими операциями Git (включая git prune, поскольку fast-import никогда не использует отдельные объекты).

fast-import не блокирует ссылки веток и тегов, которые он активно импортирует. После импорта, на этапе обновления ссылок, fast-import проверяет каждую существующую ссылку ветки, чтобы убедиться, что обновление будет перемоткой вперёд (коммит, на который указывает ссылка, содержится в новой истории записываемого коммита). Если обновление не является перемоткой вперёд, fast-import пропустит обновление этой ссылки и выведет предупреждение. fast-import всегда пытается обновить все ссылки веток и не прекращает работу после первой ошибки.

Обновление веток можно выполнить принудительно с помощью --force, но рекомендуется использовать этот параметр только в репозитории, где не выполняются другие операции. Для первоначального импорта в пустой репозиторий параметр --force не нужен.

Техническое обсуждение

fast-import отслеживает набор веток в памяти. Любую ветку можно создать или изменить в любой момент во время импорта, передав в поток ввода команду commit. Благодаря такой архитектуре фронтенд может одновременно обрабатывать неограниченное число веток, создавая коммиты в том порядке, в котором они становятся доступны из исходных данных. Это также значительно упрощает фронтенд-программы.

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

Формат ввода

За исключением необработанных файловых данных (которые Git не интерпретирует), формат ввода fast-import основан на тексте (ASCII). Такой формат упрощает разработку и отладку фронтенд-программ, особенно при использовании языков высокого уровня, например Perl, Python или Ruby.

fast-import очень строго проверяет входные данные. Под SP ниже подразумевается ровно один пробел. Аналогично, LF означает один (и только один) символ перевода строки, а HT — одну (и только одну) горизонтальную табуляцию. Лишние пробельные символы могут привести к непредвиденным результатам: например, в именах веток или файлов появятся начальные или конечные пробелы либо fast-import преждевременно завершит работу, встретив неожиданные данные.

Комментарии в потоке

Для упрощения отладки фронтендов fast-import игнорирует любую строку, начинающуюся с # (ASCII-символ решётки), вплоть до конца строки LF включительно. Строка комментария может содержать любую последовательность байтов без LF и поэтому подходит для включения подробной отладочной информации, специфичной для фронтенда и полезной при анализе потока данных fast-import.

Форматы дат

Поддерживаются следующие форматы дат. Фронтенд должен выбрать формат для этого импорта, передав его имя в параметре командной строки --date-format=<fmt>.

raw

Это собственный формат Git, имеющий вид <time> SP <offutc>. Это также формат fast-import по умолчанию, если параметр --date-format не указан.

Время события задаётся значением <time> — количеством секунд с начала эпохи UNIX (полночь 1 января 1970 года, UTC); оно записывается в виде десятичного ASCII-числа.

Локальное смещение задаётся значением <offutc> как положительное или отрицательное смещение относительно UTC. Например, EST (на 5 часов отстаёт от UTC) задаётся в <tz> значением «-0500», а UTC — «+0000». Локальное смещение не влияет на <time>; оно используется лишь как подсказка для процедур форматирования при отображении временной метки.

Если в исходных данных локальное смещение неизвестно, используйте «+0000» или наиболее распространённое локальное смещение. Например, многие организации используют репозиторий CVS, к которому обращались только пользователи из одного места и часового пояса. В этом случае можно обоснованно предположить смещение относительно UTC.

В отличие от формата rfc2822, этот формат очень строгий. Любое отклонение от заданного формата приведёт к тому, что fast-import отклонит значение; также могут выполняться некоторые проверки числовых значений на допустимость.

raw-permissive

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

rfc2822

Это стандартный формат даты, описанный в RFC 2822.

Пример значения: «Tue Feb 6 11:22:18 2007 -0500». Парсер Git точен, но довольно снисходителен к ошибкам. Это тот же парсер, который использует git am при применении патчей, полученных по электронной почте.

Некоторые некорректные строки могут быть приняты как допустимые даты. В ряде таких случаев Git всё же сможет извлечь из некорректной строки правильную дату. Есть также типы некорректных строк, которые Git разбирает неправильно, но считает допустимыми. Строки с серьёзными ошибками будут отклонены.

В отличие от описанного выше формата raw, сведения о часовом поясе и смещении относительно UTC, содержащиеся в строке даты RFC 2822, используются для преобразования даты в UTC перед сохранением. Поэтому важно, чтобы эти сведения были как можно точнее.

Если в исходных данных используются даты в формате RFC 2822, фронтенду следует поручить разбор и преобразование fast-import (вместо того чтобы выполнять их самостоятельно), поскольку парсер Git прошёл обширное тестирование в реальных условиях.

Фронтендам следует предпочитать формат raw, если в исходных данных уже используется формат эпохи UNIX, если их можно получить в этом формате или если их формат легко преобразовать в него: при разборе такого формата неоднозначность отсутствует.

now

Всегда использовать текущие дату и часовой пояс. Для <when> необходимо указывать буквальное значение now.

Это учебный формат. Текущие дата и часовой пояс системы копируются в строку идентификации во время её создания fast-import. Указать другие дату или часовой пояс невозможно.

Этот формат включён, поскольку его легко реализовать и он может пригодиться процессу, которому нужно прямо сейчас создать новый коммит без использования рабочего каталога или git update-index.

Если в команде commit используются отдельные команды author и committer, временные метки могут не совпасть, поскольку системные часы будут опрошены дважды (по одному разу для каждой команды). Единственный способ гарантировать одинаковые временные метки для сведений об авторе и коммитере — не указывать author (и тем самым скопировать значение из committer) или использовать формат даты, отличный от now.

Команды

fast-import принимает несколько команд для обновления текущего репозитория и управления текущим процессом импорта. Далее приводится более подробное описание каждой команды с примерами.

commit

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

tag

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

reset

Сбрасывает существующую (или новую) ветку до указанной ревизии. Эту команду необходимо использовать, чтобы переместить ветку на конкретную ревизию, не создавая в ней коммит.

blob

Преобразует необработанные файловые данные в blob-объект для последующего использования в команде commit. Эта команда необязательна и для выполнения импорта не требуется.

alias

Записывает, что метка ссылается на заданный объект, не создавая предварительно новый объект. Если используются --import-marks и ссылки на отсутствующие метки, fast-import завершится с ошибкой; псевдонимы позволяют присвоить допустимое значение коммитам, которые иначе были бы удалены при прореживании (например, ближайшему предку, не удалённому при прореживании).

checkpoint

Принудительно закрывает текущий pack-файл, вычисляет его уникальную контрольную сумму SHA-1 и индекс, а затем начинает новый pack-файл. Эта команда необязательна и для выполнения импорта не требуется.

progress

Заставляет fast-import вывести всю строку в собственный стандартный вывод. Эта команда необязательна и для выполнения импорта не требуется.

done

Обозначает конец потока. Эта команда необязательна, если только не запрошена возможность done с помощью параметра командной строки --done или команды feature done.

get-mark

Заставляет fast-import вывести SHA-1, соответствующий метке, в файловый дескриптор, заданный параметром --cat-blob-fd, или в stdout, если он не указан.

cat-blob

Заставляет fast-import вывести blob-объект в формате cat-file --batch в файловый дескриптор, заданный параметром --cat-blob-fd, или в stdout, если он не указан.

ls

Заставляет fast-import вывести строку с описанием записи каталога в формате ls-tree в файловый дескриптор, заданный параметром --cat-blob-fd, или в stdout, если он не указан.

feature

Включает указанную возможность. fast-import должен поддерживать эту возможность; в противном случае выполнение будет прервано.

option

Задаёт любой из перечисленных в разделе OPTIONS параметров, которые не изменяют семантику потока и соответствуют потребностям фронтенда. Эта команда необязательна и для выполнения импорта не требуется.

commit

Создаёт или обновляет ветку новым коммитом, фиксируя одно логическое изменение проекта.

        'commit' SP <ref> LF
        mark?
        original-oid?
        ('author' (SP <name>)? SP LT <email> GT SP <when> LF)?
        'committer' (SP <name>)? SP LT <email> GT SP <when> LF
        ('gpgsig' SP <algo> SP <format> LF data)?
        ('encoding' SP <encoding> LF)?
        data
        ('from' SP <commit-ish> LF)?
        ('merge' SP <commit-ish> LF)*
        (filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
        LF?

где <ref> — имя ветки, в которую нужно внести коммит. Обычно в Git перед именами веток ставится префикс refs/heads/, поэтому для импорта символа ветки CVS RELENG-1_0 в качестве значения <ref> следует использовать refs/heads/RELENG-1_0. Значение <ref> должно быть допустимым именем ссылки в Git. Поскольку LF недопустимо в имени ссылки Git, синтаксис кавычек или экранирования здесь не поддерживается.

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

Следующая за committer команда data должна содержать сообщение коммита (синтаксис команды data описан ниже). Чтобы импортировать коммит с пустым сообщением, используйте данные нулевой длины. Сообщения коммитов имеют произвольный формат, и Git их не интерпретирует. В настоящее время они должны быть закодированы в UTF-8, поскольку fast-import не позволяет указывать другие кодировки.

Перед созданием коммита для обновления содержимого ветки можно включить ноль или более команд filemodify, filedelete, filecopy, filerename, filedeleteall и notemodify. Эти команды можно указывать в любом порядке. Однако рекомендуется, чтобы в одном коммите команда filedeleteall предшествовала всем командам filemodify, filecopy, filerename и notemodify, поскольку filedeleteall очищает ветку (см. ниже).

Завершающий команду LF необязателен (раньше он был обязательным). Обратите внимание: для обеспечения обратной совместимости, если коммит заканчивается командой data (то есть в нём нет команд from, merge, filemodify, filedelete, filecopy, filerename, filedeleteall или notemodify), то в конце команды вместо одной могут следовать две команды LF.

author

Команда author может указываться необязательно, если сведения об авторе отличаются от сведений о коммитере. Если команда author опущена, fast-import автоматически использует сведения о коммитере в качестве сведений об авторе коммита. Описание полей команды author приведено ниже; они совпадают с полями команды committer.

committer

Команда committer указывает, кто создал этот коммит и когда.

Здесь <name> — отображаемое имя человека (например, «Com M Itter»), а <email> — адрес его электронной почты («cm@example.com»). LT и GT — это буквальные символы «меньше» (\x3c) и «больше» (\x3e). Они нужны, чтобы отделить адрес электронной почты от остальных полей строки. Обратите внимание: <name> и <email> имеют произвольный формат и могут содержать любую последовательность байтов, кроме LT, GT и LF. Обычно <name> кодируется в UTF-8.

Время изменения задаётся параметром <when> с использованием формата даты, выбранного параметром командной строки --date-format=<fmt>. Поддерживаемые форматы и их синтаксис перечислены выше в разделе «Форматы дат».

gpgsig

Необязательная команда gpgsig используется для добавления подписи PGP/GPG или другой криптографической подписи, заверяющей данные коммита.

        'gpgsig' SP <git-hash-algo> SP <signature-format> LF data

Команда gpgsig принимает два аргумента:

  • <git-hash-algo> указывает формат объектов Git, к которому относится подпись: sha1 или sha256. Это позволяет определить, какое представление коммита было подписано (версия SHA-1 или SHA-256), что упрощает проверку подписи и совместную работу репозиториев с разными хеш-функциями.

  • <signature-format> указывает тип подписи, например openpgp, x509, ssh или unknown. Это упрощает работу инструментов, обрабатывающих поток: им не нужно анализировать ASCII-обрамление, чтобы определить тип подписи.

Коммит может содержать не более одной подписи для формата объектов SHA-1 (хранящейся в заголовке «gpgsig») и одной для формата объектов SHA-256 (хранящейся в заголовке «gpgsig-sha256»).

Подробное описание команды data, содержащей исходные данные подписи, приведено ниже.

В текущей реализации подписи пока не проверяются. (Если установить параметр конфигурации extensions.compatObjectFormat, это может помочь проверять подписи форматов объектов SHA-1 и SHA-256, когда такая возможность будет реализована.)

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

encoding

Необязательная команда encoding указывает кодировку сообщения коммита. Большинство коммитов используют UTF-8, поэтому кодировка не указывается, но эта команда позволяет импортировать сообщения коммитов в Git без предварительного перекодирования.

from

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

Если в первом коммите новой ветки опустить команду from, fast-import создаст этот коммит без предка. Обычно это нужно только для начального коммита проекта. Если при создании новой ветки фронтенд создаёт все файлы с нуля, для начала коммита с пустым деревом можно использовать команду merge вместо from. В существующих ветках команду from обычно опускают: текущий коммит этой ветки автоматически считается первым предком нового коммита.

Поскольку LF недопустимо в имени ссылки Git или выражении SHA-1, внутри <commit-ish> не поддерживаются синтаксис кавычек или экранирования.

Здесь <commit-ish> может иметь одно из следующих значений:

  • Имя существующей ветки, уже присутствующей во внутренней таблице веток fast-import. Если fast-import не знает такого имени, оно интерпретируется как выражение SHA-1.

  • Ссылка на метку :<idnum>, где <idnum> — номер метки.

    fast-import использует : для обозначения ссылки на метку, поскольку этот символ недопустим в имени ветки Git. Начальный символ : позволяет легко отличить метку 42 (:42) от ветки 42 (42 или refs/heads/42) или сокращённого SHA-1, состоящего только из десятичных цифр.

    Прежде чем использовать метки, их необходимо объявить (с помощью mark).

  • Полный 40-байтовый или сокращённый SHA-1 коммита в шестнадцатеричном формате.

  • Любое допустимое выражение SHA-1 Git, разрешающееся в коммит. Подробности см. в разделе «SPECIFYING REVISIONS» документации gitrevisions[7].

  • Специальное нулевое значение SHA-1 (40 нулей) указывает, что ветку следует удалить.

Особый случай возобновления инкрементального импорта с текущего значения ветки следует записывать так:

        from refs/heads/branch^0

Суффикс ^0 необходим, поскольку fast-import не позволяет ветке начинаться с самой себя, а ветка создаётся в памяти ещё до того, как из входных данных будет прочитана команда from. Добавление ^0 заставляет fast-import разрешить коммит с помощью библиотеки разбора ревизий Git, а не внутренней таблицы веток, тем самым загружая существующее значение ветки.

merge

Добавляет ещё один коммит-предок. Дополнительная связь предков не меняет способ построения состояния дерева в этом коммите. Если при создании новой ветки опустить команду from, первый коммит merge станет первым предком текущего коммита, а ветка будет создана без файлов. fast-import допускает неограниченное количество команд merge на коммит, что позволяет выполнять слияния произвольного числа веток.

Здесь <commit-ish> — любое из выражений, задающих коммит и также принимаемых командой from (см. выше).

filemodify

Используется в команде commit для добавления нового файла или изменения содержимого существующего. Эта команда позволяет указать содержимое файла двумя способами.

Внешний формат данных

Данные файла уже были переданы предыдущей командой blob. Фронтенду остаётся только связать их с файлом.

        'M' SP <mode> SP <dataref> SP <path> LF

Обычно <dataref> должно быть либо ссылкой на метку (:<idnum>), заданной предыдущей командой blob, либо полным 40-байтовым SHA-1 существующего объекта blob Git. Если <mode> имеет значение 040000, то <dataref> должен быть полным 40-байтовым SHA-1 существующего объекта tree Git или ссылкой на метку, заданную командой --import-marks.

Встроенный формат данных

Данные файла ещё не переданы. Фронтенд хочет передать их в составе этой команды изменения.

        'M' SP <mode> SP 'inline' SP <path> LF
        data

Подробное описание команды data приведено ниже.

В обоих форматах <mode> — тип записи файла, указанный в восьмеричном формате. Git поддерживает только следующие режимы:

  • 100644 или 644: обычный файл (без права на выполнение). В большинстве проектов именно этот режим используется для основной части файлов. Если сомневаетесь, выбирайте его.

  • 100755 или 755: обычный файл с правом на выполнение.

  • 120000: символическая ссылка; содержимым файла будет цель ссылки.

  • 160000: gitlink; SHA-1 объекта указывает на коммит в другом репозитории. Git-ссылки можно задавать только с помощью SHA или метки коммита. Они используются для реализации подмодулей.

  • 040000: подкаталог. Подкаталоги можно задавать только с помощью SHA или метки дерева, установленной командой --import-marks.

В обоих форматах <path> — полный путь добавляемого (если его ещё нет) или изменяемого (если он уже существует) файла.

<path> можно записать как строку без кавычек или как строку в кавычках в стиле C.

Если <path> не начинается с двойной кавычки ("), это строка без кавычек, которая разбирается как буквальные байты без последовательностей экранирования. Однако если имя файла содержит LF или начинается с двойной кавычки, его нельзя представить строкой без кавычек, поэтому путь необходимо заключить в кавычки. Кроме того, исходный <path> в командах filecopy или filerename необходимо заключать в кавычки, если он содержит SP.

Если <path> начинается с двойной кавычки ("), это строка в кавычках в стиле C: полное имя файла заключается в пару двойных кавычек, а для экранирования используются специальные последовательности. Некоторые символы необходимо предварять обратной косой чертой: LF записывается как \n, обратная косая черта — как \\, а двойная кавычка — как \". Некоторые символы можно записывать с помощью последовательностей экранирования: \a для сигнала, \b для возврата на шаг, \f для перевода страницы, \n для перевода строки, \r для возврата каретки, \t для горизонтальной табуляции и \v для вертикальной табуляции. Любой байт можно записать трёхзначным восьмеричным кодом (например, \033). Все имена файлов можно представить строками в кавычках.

В <path> необходимо использовать разделители каталогов в стиле UNIX (прямую косую черту /), а значение должно быть каноническим. То есть оно не должно:

  • содержать пустой компонент каталога (например, foo//bar недопустимо);

  • заканчиваться разделителем каталогов (например, foo/ недопустимо);

  • начинаться с разделителя каталогов (например, /foo недопустимо);

  • содержать специальные компоненты . или .. (например, foo/./bar и foo/../bar недопустимы).

Корень дерева можно представить пустой строкой в качестве <path>.

<path> не может содержать NUL — ни в буквальном виде, ни в экранированной форме \000. Рекомендуется всегда кодировать <path> в UTF-8.

filedelete

Используется в команде commit для удаления файла или рекурсивного удаления всего каталога из ветки. Если после удаления файла или каталога родительский каталог опустеет, он также будет удалён автоматически. Удаление продолжится вверх по дереву до первого непустого каталога или корня.

        'D' SP <path> LF

здесь <path> — полный путь файла или подкаталога, который нужно удалить из ветки. Подробное описание <path> см. выше в разделе filemodify.

filecopy

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

        'C' SP <path> SP <path> LF

здесь первый <path> — исходное расположение, а второй <path> — место назначения. Подробное описание допустимого формата <path> см. выше в разделе filemodify. Чтобы использовать исходный путь, содержащий SP, его необходимо заключить в кавычки.

Команда filecopy выполняется немедленно. После копирования исходного расположения в место назначения любые последующие команды, применённые к исходному расположению, не повлияют на копию.

filerename

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

        'R' SP <path> SP <path> LF

здесь первый <path> — исходное расположение, а второй <path> — место назначения. Подробное описание допустимого формата <path> см. выше в разделе filemodify. Чтобы использовать исходный путь, содержащий SP, его необходимо заключить в кавычки.

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

Обратите внимание: команда filerename эквивалентна команде filecopy, за которой следует команда filedelete для исходного расположения. Использование filerename даёт небольшое преимущество в производительности, однако оно настолько незначительно, что преобразовывать пару удаления и добавления в исходных данных в переименование для fast-import никогда не стоит. Команда filerename предусмотрена лишь для упрощения работы фронтендов, в которых уже есть сведения о переименованиях и которые не хотят разбирать их на команду filecopy с последующей командой filedelete.

filedeleteall

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

        'deleteall' LF

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

Вызов команды filedeleteall с последующими командами filemodify, необходимыми для задания правильного содержимого, даст тот же результат, что и отправка только нужных команд filemodify и filedelete. Однако подход с использованием filedeleteall может потребовать от fast-import немного больше памяти на каждую активную ветку (менее 1 МиБ даже для очень крупных проектов). Поэтому фронтендам, которые могут легко получить только затронутые пути для коммита, рекомендуется поступать именно так.

notemodify

Используется в команде commit <notes-ref> для добавления новой заметки с аннотацией <commit-ish> или изменения содержимого этой аннотации. Внутри эта команда аналогична filemodify 100644 для пути <commit-ish> (возможно, разбитого на подкаталоги). Для записи в дерево <notes-ref> не рекомендуется использовать какие-либо другие команды, кроме filedeleteall, которая удаляет все существующие заметки в этом дереве. Содержимое заметки можно указать двумя способами.

Внешний формат данных

Данные заметки уже были переданы предыдущей командой blob. Фронтенду остаётся только связать их с коммитом, который нужно снабдить аннотацией.

        'N' SP <dataref> SP <commit-ish> LF

Здесь <dataref> может быть либо ссылкой на метку (:<idnum>), заданной предыдущей командой blob, либо полным 40-байтовым SHA-1 существующего объекта blob Git.

Встроенный формат данных

Данные заметки ещё не переданы. Фронтенд хочет передать их в составе этой команды изменения.

        'N' SP 'inline' SP <commit-ish> LF
        data

Подробное описание команды data приведено ниже.

В обоих форматах <commit-ish> — любое из выражений, задающих коммит и также принимаемых командой from (см. выше).

mark

Указывает fast-import сохранить ссылку на текущий объект, чтобы фронтенд мог обратиться к нему в будущем, не зная его SHA-1. Здесь текущим объектом является объект, создаваемый командой, внутри которой находится команда mark. Это может быть commit, tag или blob, но чаще всего используется commit.

        'mark' SP ':' <idnum> LF

где <idnum> — номер метки, назначенный ей фронтендом. Значение <idnum> записывается десятичным целым числом в кодировке ASCII. Значение 0 зарезервировано и не может использоваться как метка. В качестве меток допустимы только значения, большие или равные 1.

Новые метки создаются автоматически. Существующие метки можно переназначить другому объекту, просто повторно использовав то же значение <idnum> в другой команде mark.

original-oid

Указывает имя объекта в исходной системе управления версиями. fast-import просто игнорирует эту директиву, однако она может быть полезна фильтрующим процессам, которые обрабатывают и изменяют поток перед передачей в fast-import.

        'original-oid' SP <object-identifier> LF

где <object-identifier> — любая строка, не содержащая LF.

tag

Создаёт аннотированный тег, указывающий на определённый коммит. Чтобы создать облегчённые (без аннотации) теги, см. команду reset ниже.

        'tag' SP <name> LF
        mark?
        'from' SP <commit-ish> LF
        original-oid?
        'tagger' (SP <name>)? SP LT <email> GT SP <when> LF
        data

где <name> — имя создаваемого тега.

При сохранении в Git к именам тегов автоматически добавляется префикс refs/tags/, поэтому для импорта символа ветки CVS RELENG-1_0-FINAL в качестве <name> достаточно указать RELENG-1_0-FINAL, и fast-import запишет соответствующую ссылку как refs/tags/RELENG-1_0-FINAL.

Значение <name> должно быть допустимым именем ссылки в Git и поэтому может содержать косые черты. Поскольку LF недопустим в имени ссылки Git, здесь не поддерживается синтаксис заключения в кавычки или экранирования.

Команда from такая же, как в команде commit; подробности см. выше.

Команда tagger использует тот же формат, что и committer в commit; подробности также см. выше.

Команда data, следующая за tagger, должна предоставлять сообщение аннотированного тега (синтаксис команды data см. ниже). Чтобы импортировать пустое сообщение тега, укажите данные нулевой длины. Сообщения тегов имеют произвольный формат и не интерпретируются Git. В настоящее время они должны быть закодированы в UTF-8, поскольку fast-import не позволяет указывать другие кодировки.

Подписывать аннотированные теги во время импорта из fast-import нельзя. Не рекомендуется пытаться включить собственную подпись PGP/GPG, поскольку интерфейсная программа не имеет (простого) доступа к полному набору байтов, которые обычно входят в такую подпись. Если подпись необходима, создайте с помощью reset облегчённые теги из fast-import, а затем создайте для них аннотированные версии вне программы, используя стандартный процесс git tag.

reset

Создаёт (или пересоздаёт) указанную ветку, при необходимости начиная с определённой ревизии. Команда reset позволяет интерфейсной программе выдать новую команду from для существующей ветки или создать новую ветку на основе существующего коммита, не создавая новый коммит.

        'reset' SP <ref> LF
        ('from' SP <commit-ish> LF)?
        LF?

Подробное описание <ref> и <commit-ish> см. выше в разделах commit и from.

Команда LF после этой команды необязательна (раньше она была обязательной).

Команду reset также можно использовать для создания облегчённых (без аннотации) тегов. Например:

reset refs/tags/938
from :938

создаст облегчённый тег refs/tags/938, указывающий на коммит, на который ссылается метка :938.

blob

Запрашивает запись одной версии файла в pack-файл. Эта версия не связана ни с одним коммитом; связь должна быть установлена последующей командой commit, которая ссылается на blob через назначенную метку.

        'blob' LF
        mark?
        original-oid?
        data

Здесь команда mark необязательна, поскольку некоторые интерфейсные программы генерируют Git SHA-1 для blob самостоятельно и напрямую передают его команде commit. Однако обычно это не стоит затраченных усилий, поскольку хранить метки недорого, а пользоваться ими просто.

data

Передаёт в fast-import необработанные данные (для использования в качестве содержимого blob/файла, сообщений коммитов или сообщений аннотированных тегов). Данные можно передать, указав точное количество байтов или ограничив их завершающей строкой. Интерфейсные программы для преобразований производственного качества всегда должны использовать формат с точным количеством байтов, поскольку он надёжнее и эффективнее. Формат с разделителем предназначен главным образом для тестирования fast-import.

Строки комментариев, встречающиеся в части <raw> команд data, всегда считаются частью тела данных и поэтому никогда не игнорируются fast-import. Это позволяет безопасно импортировать содержимое любых файлов и сообщений, строки которых могут начинаться с #.

Формат с точным количеством байтов

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

        'data' SP <count> LF
        <raw> LF?

где <count> — точное количество байтов в <raw>. Значение <count> задаётся десятичным целым числом в кодировке ASCII. Символ LF по обе стороны от <raw> не учитывается в <count> и не включается в импортированные данные.

Символ LF после <raw> необязателен (раньше он был обязательным), но рекомендуется. Если всегда включать его, отлаживать поток fast-import будет проще: следующая команда всегда будет начинаться с нулевого столбца следующей строки, даже если <raw> не заканчивалось символом LF.

Формат с разделителем

Для обозначения конца данных используется строка-разделитель. fast-import вычисляет длину, находя разделитель. Этот формат полезен главным образом для тестирования и не рекомендуется для реальных данных.

        'data' SP '<<' <delim> LF
        <raw> LF
        <delim> LF
        LF?

где <delim> — выбранная строка-разделитель. Строка <delim> не должна встречаться отдельно в строке внутри <raw>, иначе fast-import решит, что данные закончились раньше времени. Символ LF, непосредственно следующий за <raw>, является частью <raw>. Это одно из ограничений формата с разделителем: невозможно передать фрагмент данных, последний байт которого не является LF.

Символ LF после <delim> LF необязателен (раньше он был обязательным).

alias

Записывает, что метка ссылается на заданный объект, не создавая предварительно нового объекта.

        'alias' LF
        mark
        'to' SP <commit-ish> LF
        LF?

Подробное описание <commit-ish> см. выше в разделе from.

checkpoint

Принудительно закрывает текущий pack-файл, начинает новый и сохраняет все текущие ссылки веток, теги и метки.

        'checkpoint' LF
        LF?

Обратите внимание: fast-import автоматически переключает pack-файлы, когда текущий pack-файл достигает размера --max-pack-size или 4 ГиБ — в зависимости от того, какой предел меньше. При автоматическом переключении pack-файла fast-import не обновляет ссылки веток, теги или метки.

Поскольку выполнение команды checkpoint может потребовать значительного времени процессора и операций ввода-вывода с диском (для вычисления контрольной суммы SHA-1 всего pack-файла, создания соответствующего индексного файла и обновления ссылок), выполнение одной команды checkpoint может легко занять несколько минут.

Интерфейсные программы могут создавать контрольные точки во время очень крупных и длительных импортов или когда необходимо предоставить другому процессу Git доступ к ветке. Однако репозиторий Subversion размером 30 ГиБ можно загрузить в Git с помощью fast-import примерно за 3 часа, поэтому явное создание контрольных точек может быть не нужно.

Символ LF после команды необязателен (раньше он был обязательным).

progress

При обработке команды во входном потоке fast-import выводит всю строку progress без изменений в стандартный канал вывода (дескриптор файла 1). В остальном команда не влияет на текущий импорт или внутреннее состояние fast-import.

        'progress' SP <any> LF
        LF?

Часть команды <any> может содержать любую последовательность байтов, не содержащую LF. Символ LF после команды необязателен. Вывод можно обработать с помощью такого инструмента, как sed, чтобы удалить начальную часть строки. Например:

frontend | git fast-import | sed 's/^progress //'

Команда progress, размещённая сразу после checkpoint, сообщит читателю о завершении checkpoint, после чего можно безопасно обращаться к ссылкам, обновлённым fast-import.

get-mark

Заставляет fast-import вывести SHA-1, соответствующий метке, в stdout или в дескриптор файла, заданный ранее аргументом --cat-blob-fd. В остальном команда не влияет на текущий импорт; она предназначена для получения SHA-1, на которые могут ссылаться более поздние коммиты в своих сообщениях.

        'get-mark' SP ':' <idnum> LF

Подробные сведения о безопасном чтении этого вывода см. ниже в разделе «Ответы на команды».

cat-blob

Заставляет fast-import вывести blob в дескриптор файла, заданный ранее аргументом --cat-blob-fd. В остальном команда не влияет на текущий импорт; её основное назначение — извлекать blob, которые могут находиться в памяти fast-import, но недоступны в целевом репозитории.

        'cat-blob' SP <dataref> LF

<dataref> может быть ссылкой на ранее заданную метку (:<idnum>) или полным 40-байтовым SHA-1 blob Git, уже существующего или готового к записи.

Вывод имеет тот же формат, что и git cat-file --batch:

<sha1> SP 'blob' SP <size> LF
<contents> LF

Эту команду можно использовать там, где может располагаться директива filemodify, в том числе в середине коммита. Для filemodify с директивой inline её также можно разместить непосредственно перед директивой data.

Подробные сведения о безопасном чтении этого вывода см. ниже в разделе «Ответы на команды».

ls

Выводит сведения об объекте по указанному пути в дескриптор файла, заданный ранее аргументом --cat-blob-fd. Это позволяет вывести blob из активного коммита (с помощью cat-blob) или скопировать blob или дерево из предыдущего коммита для использования в текущем (с помощью filemodify).

Команду ls также можно использовать там, где может располагаться директива filemodify, в том числе в середине коммита.

Чтение из активного коммита

Эту форму можно использовать только в середине команды commit. Путь задаёт запись каталога в активном коммите fast-import. В этом случае путь должен быть заключён в кавычки.

        'ls' SP <path> LF
Чтение из указанного дерева

<dataref> может быть ссылкой на метку (:<idnum>) или полным 40-байтовым SHA-1 объекта-тега, коммита или дерева Git, уже существующего или ожидающего записи. Путь задаётся относительно верхнего уровня дерева, указанного в <dataref>.

        'ls' SP <dataref> SP <path> LF

Подробное описание <path> см. выше в разделе filemodify.

Вывод имеет тот же формат, что и git ls-tree <tree> -- <path>:

<mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF

<dataref> представляет объект blob, tree или commit по пути <path> и может использоваться в последующих командах get-mark, cat-blob, filemodify или ls.

Если по этому пути нет файла или поддерева, git fast-import сообщит:

missing SP <path> LF

Подробные сведения о безопасном чтении этого вывода см. ниже в разделе «Ответы на команды».

feature

Требует, чтобы fast-import поддерживал указанную функцию, и прерывает работу, если это не так.

        'feature' SP <feature> ('=' <argument>)? LF

В качестве части <feature> команды можно указать одно из следующих значений:

date-format
export-marks
relative-marks
no-relative-marks
force

Действует так, как если бы в командной строке был указан соответствующий параметр с ведущим символом -- (см. раздел ПАРАМЕТРЫ выше).

import-marks
import-marks-if-exists

Аналогично --import-marks, но с двумя отличиями: во-первых, в потоке допускается только одна команда «feature import-marks» или «feature import-marks-if-exists»; во-вторых, параметр командной строки --import-marks= или --import-marks-if-exists переопределяет любую из этих команд «feature» в потоке; в-третьих, «feature import-marks-if-exists», как и соответствующий параметр командной строки, молча пропускает несуществующий файл.

get-mark
cat-blob
ls

Требует, чтобы серверная часть поддерживала соответственно команды get-mark, cat-blob или ls. Версии fast-import, не поддерживающие указанную команду, завершат работу с соответствующим сообщением. Это позволяет быстро завершить импорт с понятным сообщением об ошибке, а не тратить время на начальную часть импорта до обнаружения неподдерживаемой команды.

notes

Требует, чтобы серверная часть поддерживала подкоманду notemodify (N) команды commit. Версии fast-import, не поддерживающие заметки, завершат работу с соответствующим сообщением.

done

Выдаёт ошибку, если поток завершается без команды done. Без этой функции ошибки, из-за которых интерфейсная программа внезапно завершает работу в удобном месте потока, могут остаться незамеченными. Такое может произойти, например, если интерфейсная программа импорта аварийно завершится в середине операции, не отправив SIGTERM или SIGKILL своему подчинённому экземпляру git fast-import.

option

Обрабатывает указанный параметр, чтобы git fast-import работал в соответствии с потребностями интерфейсной программы. Обратите внимание: параметры, указанные интерфейсной программой, переопределяются любыми параметрами, которые пользователь может передать непосредственно git fast-import.

    'option' SP <option> LF

В качестве части команды <option> можно указать любой параметр из раздела ПАРАМЕТРЫ, который не меняет семантику импорта, без ведущего символа --; такой параметр обрабатывается обычным образом.

Команды option должны быть первыми во входном потоке (не считая команд feature); команда option после любой команды, не являющейся option, считается ошибкой.

Следующие параметры командной строки меняют семантику импорта, поэтому их нельзя передавать как option:

  • date-format

  • import-marks

  • export-marks

  • cat-blob-fd

  • force

done

Если функция done не используется, эта команда обрабатывается так, как если бы был прочитан EOF. Её можно использовать, чтобы указать fast-import завершить работу досрочно.

Если используется параметр командной строки --done или команда feature done, команда done обязательна и обозначает конец потока.

Ответы на команды

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

Однако некоторым интерфейсным программам полезно иметь возможность считывать данные из обновляемого репозитория (например, когда исходные материалы описывают объекты как патчи, применяемые к ранее импортированным объектам). Это можно сделать, связав интерфейсную программу и fast-import двунаправленными каналами:

mkfifo fast-import-output
frontend <fast-import-output |
git fast-import >fast-import-output

Интерфейсная программа, настроенная таким образом, может использовать команды progress, get-mark, ls и cat-blob для чтения сведений о выполняющемся импорте.

Чтобы избежать взаимной блокировки, такие интерфейсные программы должны полностью считывать все ожидающие выходные данные от progress, ls, get-mark и cat-blob прежде, чем выполнять записи в fast-import, которые могут заблокироваться.

Отчёты об аварийном завершении

Если fast-import получает недопустимые входные данные, он завершает работу с ненулевым кодом возврата и создаёт отчёт об аварийном завершении в корневом каталоге репозитория Git, в который выполнялся импорт. Отчёты содержат снимок внутреннего состояния fast-import, а также последние команды, приведшие к сбою.

В истории команд отчёта отображаются все недавние команды (включая комментарии потока, изменения файлов и команды progress), но необработанные данные файлов и сообщения коммитов в отчёт не включаются. Это экономит место в файле отчёта и сокращает объём буферизации, необходимой fast-import во время выполнения.

После записи отчёта fast-import закроет текущий pack-файл и экспортирует таблицу меток. Это позволит разработчику интерфейсной программы проверить состояние репозитория и возобновить импорт с места сбоя. При аварийном завершении изменённые ветки и теги не обновляются, поскольку импорт не завершился успешно. Сведения о ветках и тегах можно найти в отчёте; если обновление необходимо, применить их нужно вручную.

Пример аварийного завершения:

$ cat >in <<END_OF_INPUT
# my very first test commit
commit refs/heads/master
committer Shawn O. Pearce <spearce> 19283 -0400
# who is that guy anyway?
data <<EOF
this is my commit
EOF
M 644 inline .gitignore
data <<EOF
.gitignore
EOF
M 777 inline bob
END_OF_INPUT
$ git fast-import <in
fatal: Corrupt mode: M 777 inline bob
fast-import: dumping crash report to .git/fast_import_crash_8434
$ cat .git/fast_import_crash_8434
fast-import crash report:
    fast-import process: 8434
    parent process     : 1391
    at Sat Sep 1 00:58:12 2007
fatal: Corrupt mode: M 777 inline bob
Most Recent Commands Before Crash
---------------------------------
  # my very first test commit
  commit refs/heads/master
  committer Shawn O. Pearce <spearce> 19283 -0400
  # who is that guy anyway?
  data <<EOF
  M 644 inline .gitignore
  data <<EOF
* M 777 inline bob
Active Branch LRU
-----------------
    active_branches = 1 cur, 5 max
pos  clock name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1)      0 refs/heads/master
Inactive Branches
-----------------
refs/heads/master:
  status      : active loaded dirty
  tip commit  : 0000000000000000000000000000000000000000
  old tree    : 0000000000000000000000000000000000000000
  cur tree    : 0000000000000000000000000000000000000000
  commit clock: 0
  last pack   :
-------------------
END OF CRASH REPORT

Советы и рекомендации

Ниже приведены советы и рекомендации, собранные у разных пользователей fast-import.

Используйте отдельную метку для каждого коммита

При преобразовании репозитория используйте уникальную метку для каждого коммита (mark :<n>) и укажите параметр --export-marks в командной строке. fast-import создаст файл со списком всех меток и соответствующих им SHA-1 объектов Git. Если интерфейсная программа может связать метки с исходным репозиторием, точность и полноту импорта легко проверить, сравнив каждый коммит Git с соответствующей исходной ревизией.

Если исходная система — например, Perforce или Subversion, это должно быть несложно: метка fast-import может совпадать с номером набора изменений Perforce или номером ревизии Subversion.

Свободно переключайтесь между ветками

Не пытайтесь оптимизировать интерфейсную программу так, чтобы во время импорта она обрабатывала только одну ветку за раз. Хотя это может немного ускорить работу fast-import, сложность кода интерфейсной программы заметно возрастёт.

Встроенный в fast-import механизм LRU для веток работает очень хорошо, а затраты на активацию неактивной ветки настолько малы, что переключение между ветками практически не влияет на производительность импорта.

Обработка переименований

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

Используйте вспомогательные ветки для исправления тегов

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

Импортировать такие теги в Git как есть невозможно, не создав хотя бы один коммит, который «исправит» файлы в соответствии с содержимым тега. Используйте команду reset fast-import, чтобы сбросить фиктивную ветку за пределами пространства имён обычных веток до базового коммита тега, затем создайте один или несколько коммитов с исправлениями файлов и, наконец, пометьте фиктивную ветку тегом.

Например, поскольку все обычные ветки хранятся под именем refs/heads/, назовите вспомогательную ветку для исправления тегов TAG_FIXUP. Так вспомогательная ветка импортёра не сможет конфликтовать по пространству имён с реальными ветками, импортированными из источника (имя TAG_FIXUP не является refs/heads/TAG_FIXUP).

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

После завершения fast-import интерфейсной программе нужно выполнить rm .git/TAG_FIXUP, чтобы удалить фиктивную ветку.

Сначала импортируйте, перепакуйте позже

Сразу после завершения fast-import репозиторий Git полностью исправен и готов к использованию. Обычно это занимает совсем немного времени, даже для довольно крупных проектов (более 100 000 коммитов).

Однако для повышения локальности данных и производительности доступа необходимо перепаковать репозиторий. Для очень крупных проектов это также может занять несколько часов (особенно при использовании -f и большого значения параметра --window). Поскольку перепаковку можно безопасно выполнять параллельно с чтением и записью, запустите её в фоновом режиме и дождитесь завершения. Нет причин откладывать знакомство с новым проектом Git!

Если вы решили дождаться завершения перепаковки, не запускайте тесты производительности, пока она не закончится. fast-import создаёт неоптимальные pack-файлы, которые просто не встречаются в реальных сценариях использования.

Перепаковка исторических данных

Если вы перепаковываете очень старые импортированные данные (например, старше года), подумайте о том, чтобы потратить дополнительное время процессора и указать --window=50 (или больше) при запуске git repack. Это займёт больше времени, но позволит создать pack-файл меньшего размера. Потратить усилия нужно только один раз, а меньший размер репозитория будет полезен всем участникам проекта.

Добавляйте сообщения о ходе выполнения

Время от времени интерфейсная программа должна отправлять fast-import сообщение progress. Содержимое таких сообщений может быть произвольным; например, можно выводить текущий месяц и год всякий раз, когда дата текущего коммита переходит на следующий месяц. Пользователям будет спокойнее, если они будут знать, какая часть потока данных уже обработана.

Оптимизация pack-файлов

При упаковке блоба fast-import всегда пытается создать дельту относительно последнего записанного блоба. Если фронтенд специально не организует этот процесс, скорее всего, это будет не предыдущая версия того же файла, поэтому созданная дельта не будет минимально возможной. Полученный пакетный файл будет сжат, но не оптимизирован.

Фронтенды, которые эффективно имеют доступ ко всем ревизиям одного файла (например, читают файл RCS/CVS ,v), могут передать все ревизии этого файла как последовательность идущих подряд команд blob. Это позволяет fast-import создавать дельты между разными ревизиями файла, экономя место в итоговом пакетном файле. Метки можно использовать, чтобы позднее идентифицировать отдельные ревизии файла в последовательности команд commit.

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

По этой причине настоятельно рекомендуется после завершения работы fast-import перепаковать репозиторий с помощью git repack -a -d, чтобы Git мог реорганизовать пакетные файлы для более быстрого доступа к данным. Если дельты блобов неоптимальны (см. выше), добавление параметра -f для принудительного пересчёта всех дельт также может значительно уменьшить размер итогового пакетного файла (уменьшение на 30–50% — обычное дело).

Вместо запуска git repack можно также запустить git gc --aggressive, которая также оптимизирует другие элементы после импорта (например, упакует свободные ссылки). Как отмечено в разделе «AGGRESSIVE» в документации git-gc[1], параметр --aggressive найдёт новые дельты с параметром -f команды git-repack[1]. По причинам, описанным выше, использование --aggressive после fast-import — один из немногих случаев, когда известно, что это оправданно.

Использование памяти

На объём памяти, необходимый fast-import для выполнения импорта, влияет ряд факторов. Подобно критическим участкам основного кода Git, fast-import использует собственные аллокаторы памяти, чтобы распределить накладные расходы, связанные с malloc. На практике fast-import, благодаря использованию крупных блоков памяти, сводит накладные расходы malloc к нулю.

на объект

fast-import хранит в памяти структуру для каждого объекта, записанного в ходе выполнения. В 32-разрядной системе структура занимает 32 байта, в 64-разрядной — 40 байт (из-за большего размера указателей). Объекты в таблице не освобождаются до завершения fast-import. Импорт 2 миллионов объектов в 32-разрядной системе потребует примерно 64 МиБ памяти.

Таблица объектов фактически является хеш-таблицей с ключом в виде имени объекта (уникального SHA-1). Такая конфигурация хранилища позволяет fast-import повторно использовать существующий или уже записанный объект и не записывать дубликаты в выходной пакетный файл. Дубликаты блобов при импорте встречаются на удивление часто, обычно из-за слияния веток в исходном проекте.

на метку

Метки хранятся в разреженном массиве, где на каждую метку приходится 1 указатель (4 или 8 байт в зависимости от размера указателя). Хотя массив разреженный, фронтендам всё же настоятельно рекомендуется использовать метки от 1 до n, где n — общее число меток, необходимых для импорта.

на ветку

Ветки делятся на активные и неактивные. Использование памяти этими двумя категориями существенно различается.

Неактивные ветки хранятся в структуре размером 96 или 120 байт (для 32- или 64-разрядных систем соответственно) плюс длина имени ветки (обычно менее 200 байт) на ветку. fast-import без труда обрабатывает до 10 000 неактивных веток, используя менее 2 МиБ памяти.

Активные ветки имеют такие же накладные расходы, как и неактивные, но также содержат копии всех деревьев, недавно изменённых в этой ветке. Если поддерево include не изменялось с тех пор, как ветка стала активной, его содержимое не будет загружено в память. Но если поддерево src изменялось коммитом после активации ветки, его содержимое будет загружено в память.

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

fast-import автоматически переводит активные ветки в неактивное состояние, используя простой алгоритм вытеснения наименее недавно использовавшихся веток. Цепочка LRU обновляется при выполнении каждой команды commit. Максимальное число активных веток можно увеличить или уменьшить в командной строке с помощью параметра --active-branches=.

на активное дерево

Деревья (то есть каталоги) занимают всего 12 байт памяти сверх памяти, необходимой для их записей (см. ниже раздел «на активную запись файла»). Затраты на дерево практически равны нулю, поскольку его накладные расходы распределяются между отдельными записями файлов.

на активную запись файла

Для файлов (и указателей на поддеревья) в активных деревьях требуется 52 или 64 байта на запись (для 32- и 64-разрядных платформ соответственно). Для экономии места имена файлов и деревьев хранятся в общем пуле строк, поэтому имя файла «Makefile» занимает всего 16 байт (с учётом накладных расходов заголовка строки), независимо от того, сколько раз оно встречается в проекте.

Сочетание LRU для активных веток, пула строк для имён файлов и отложенной загрузки поддеревьев позволяет fast-import эффективно импортировать проекты с более чем 2 000 веток и 45 114 файлами, используя очень мало памяти (менее 2,7 МиБ на активную ветку).

Сигналы

Отправка сигнала SIGUSR1 процессу git fast-import досрочно завершает создание текущего пакетного файла, имитируя команду checkpoint. Нетерпеливый оператор может воспользоваться этой возможностью, чтобы просмотреть объекты и ссылки в ходе импорта, пожертвовав дополнительным временем выполнения и качеством сжатия.

Настройка

Всё содержимое этого раздела ниже данной строки выборочно включено из документации git-config[1]. Здесь приведён тот же материал, что и в ней:

fastimport.unpackLimit

Если число объектов, импортированных командой git-fast-import[1], меньше этого предела, объекты будут распакованы в отдельные файлы объектов. Если же число импортированных объектов равно этому пределу или превышает его, пакет будет сохранён как пакетный файл. Сохранение пакета, созданного fast-import, может ускорить завершение операции импорта, особенно на медленных файловых системах. Если значение не задано, вместо него используется значение transfer.unpackLimit.

См. также

git-fast-export[1]

fast-import

© 2005–2026 Linus Torvalds and others
Licensed under the GNU General Public License version 2.
https://git-scm.com/docs/git-fast-import

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API