gitprotocol-v2
Название
gitprotocol-v2 — протокол обмена Git, версия 2
Краткое описание
<over-the-wire-protocol>
Описание
В этом документе представлена спецификация версии 2 протокола обмена Git. Протокол v2 улучшает v1 следующим образом:
-
Вместо нескольких имён служб одна служба будет поддерживать несколько команд
-
Легко расширяется, поскольку возможности вынесены в отдельный раздел протокола и больше не скрываются за байтом NUL и не ограничены размером pkt-line
-
Отдельно передаётся другая информация, скрытая за байтами NUL (например, строка агента как возможность, а symrefs можно запросить с помощью
ls-refs) -
Объявление ссылок пропускается, если оно не запрошено явно
-
Команда ls-refs позволяет явно запрашивать отдельные ссылки
-
Спроектирован с учётом http и stateless-rpc. Благодаря чёткой семантике сброса удалённый помощник http может просто работать как прокси
В протоколе v2 обмен данными ориентирован на команды. При первом обращении к серверу объявляется список возможностей. Некоторые из этих возможностей представляют собой команды, выполнение которых может запросить клиент. После завершения команды клиент может повторно использовать соединение и запросить выполнение других команд.
Форматирование строк пакетов
Как и в v1, весь обмен данными выполняется с использованием формата строк пакетов. Дополнительные сведения см. в документах gitprotocol-pack[5] и gitprotocol-common[5].
В протоколе v2 эти специальные пакеты имеют следующую семантику:
-
0000Пакет сброса (flush-pkt) — обозначает конец сообщения -
0001Пакет-разделитель (delim-pkt) — разделяет части сообщения -
0002Пакет конца ответа (response-end-pkt) — обозначает конец ответа для соединений без сохранения состояния
Первоначальный запрос клиента
Как правило, клиент может запросить использование протокола v2, отправив version=2 через соответствующий дополнительный канал используемого транспорта, что неизбежно устанавливает GIT_PROTOCOL. Дополнительные сведения приведены в документах gitprotocol-pack[5] и gitprotocol-http[5], а также в определении GIT_PROTOCOL в git[1]. Во всех случаях сервер отвечает объявлением возможностей.
Транспорт Git
При использовании транспорта git:// можно запросить протокол v2, отправив «version=2» в качестве дополнительного параметра:
003egit-upload-pack /project.git\0host=myserver.com\0\0version=2\0
Транспорт SSH и файловый транспорт
При использовании транспорта ssh:// или file:// необходимо явно задать переменную окружения GIT_PROTOCOL, включив в неё «version=2». Возможно, потребуется настроить сервер, чтобы он разрешал передачу этой переменной окружения.
Транспорт HTTP
При использовании транспорта http:// или https:// клиент отправляет «умный» запрос info/refs, описанный в gitprotocol-http[5], и запрашивает использование v2, передавая «version=2» в заголовке Git-Protocol.
C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0 C: Git-Protocol: version=2
Сервер v2 ответит следующим образом:
S: 200 OK S: <Some headers> S: ... S: S: 000eversion 2\n S: <capability-advertisement>
Последующие запросы отправляются напрямую службе $GIT_URL/git-upload-pack. (То же самое работает и для git-receive-pack.)
Используется параметр --http-backend-info-refs команды git-upload-pack[1].
Возможно, потребуется настроить сервер для передачи содержимого этого заголовка через переменную GIT_PROTOCOL. См. обсуждение в git-http-backend[1].
Объявление возможностей
Сервер, решивший использовать протокол версии 2 для обмена данными (на основании запроса клиента), уведомляет клиента, отправляя в первоначальном ответе строку версии, за которой следует объявление возможностей. Каждая возможность представляет собой ключ с необязательным значением. Клиенты должны игнорировать все неизвестные ключи. Семантика неизвестных значений определяется отдельно для каждого ключа. Некоторые возможности описывают команды, выполнение которых может запросить клиент.
capability-advertisement = protocol-version
capability-list
flush-pkt protocol-version = PKT-LINE("version 2" LF)
capability-list = *capability
capability = PKT-LINE(key[=value] LF) key = 1*(ALPHA | DIGIT | "-_")
value = 1*(ALPHA | DIGIT | " -_.,?\/{}[]()<>!@#$%^&*+=:;") Запрос команды
Получив объявление возможностей, клиент может отправить запрос на выбор нужной команды, указав любые необходимые возможности или аргументы. Затем следует необязательная часть, в которой клиент может передать параметры или запросы, относящиеся к конкретной команде. За один раз можно запросить только одну команду.
request = empty-request | command-request
empty-request = flush-pkt
command-request = command
capability-list
delim-pkt
command-args
flush-pkt
command = PKT-LINE("command=" key LF)
command-args = *command-specific-arg command-specific-args are packet line framed arguments defined by each individual command.
Затем сервер проверит, содержит ли запрос клиента допустимую команду и допустимые возможности, которые были объявлены. Если запрос корректен, сервер выполнит команду. Сервер ОБЯЗАН дождаться получения всего запроса клиента, прежде чем отправлять ответ. Формат ответа определяется выполняемой командой, но во всех случаях пакет сброса (flush-pkt) обозначает конец ответа.
После завершения команды и получения клиентом полного ответа от сервера клиент может запросить выполнение другой команды или закрыть соединение. По желанию клиент может отправить пустой запрос, состоящий только из пакета сброса (flush-pkt), чтобы указать, что больше запросов не будет.
Возможности
Существует два разных типа возможностей: обычные возможности, которые можно использовать для передачи информации или изменения поведения запроса, и команды — основные действия, которые клиент хочет выполнить (fetch, push и т. д.).
По умолчанию протокол версии 2 не сохраняет состояние. Это означает, что все команды должны выполняться за один раунд и не зависеть от состояния на стороне сервера, если только клиент не запросил возможность, указывающую, что сервер должен сохранять состояние. Клиенты НЕ ДОЛЖНЫ зависеть от управления состоянием на стороне сервера для корректной работы. Это позволяет использовать простую балансировку нагрузки по схеме round-robin на стороне сервера без необходимости учитывать управление состоянием.
agent
Сервер может объявить возможность agent со значением X (в форме agent=X), чтобы сообщить клиенту, что сервер работает под управлением версии X. Клиент может отправить собственную строку агента, включив возможность agent со значением Y (в форме agent=Y) в запрос к серверу (но он НЕ ДОЛЖЕН этого делать, если сервер не объявил возможность agent). Строки X и Y могут содержать любые печатные символы ASCII, кроме пробела (то есть байты в диапазоне 33 ⇐ x ⇐ 126), и обычно имеют форму "package/version-os" (например, "git/1.8.3.1-Linux"), где os — название операционной системы (например, "Linux"). Значения X и Y можно настроить с помощью переменной среды GIT_USER_AGENT, которая имеет приоритет. Значение os получается из поля sysname системного вызова uname(2) или его аналога. Строки агента носят исключительно информационный характер и предназначены для статистики и отладки; их НЕЛЬЗЯ использовать для программных предположений о наличии или отсутствии определённых возможностей.
ls-refs
ls-refs — команда, используемая в v2 для запроса объявления ссылок. В отличие от текущего объявления ссылок, ls-refs принимает аргументы, с помощью которых можно ограничить набор ссылок, отправляемых сервером.
Дополнительные возможности, не поддерживаемые базовой командой, объявляются как значение команды в объявлении возможностей в виде списка возможностей, разделённых пробелами: "<command>=<feature-1> <feature-2>"
Команда ls-refs принимает следующие аргументы:
symrefs In addition to the object pointed by it, show the underlying ref pointed by it when showing a symbolic ref. peel Show peeled tags. ref-prefix <prefix> When specified, only references having a prefix matching one of the provided prefixes are displayed. Multiple instances may be given, in which case references matching any prefix will be shown. Note that this is purely for optimization; a server MAY show refs not matching the prefix if it chooses, and clients should filter the result themselves.
Если объявлена возможность unborn, в запрос клиента можно включить следующий аргумент.
unborn The server will send information about HEAD even if it is a symref pointing to an unborn branch in the form "unborn HEAD symref-target:<target>".
Вывод ls-refs имеет следующий вид:
output = *ref flush-pkt obj-id-or-unborn = (obj-id | "unborn") ref = PKT-LINE(obj-id-or-unborn SP refname *(SP ref-attribute) LF) ref-attribute = (symref | peeled) symref = "symref-target:" symref-target peeled = "peeled:" obj-id
fetch
fetch — команда, используемая в v2 для получения packfile. Её можно рассматривать как изменённую версию fetch из v1, в которой удалено объявление ссылок (поскольку эту роль выполняет команда ls-refs), а формат сообщений скорректирован для устранения избыточности и упрощения добавления будущих расширений.
Дополнительные возможности, не поддерживаемые базовой командой, объявляются как значение команды в объявлении возможностей в виде списка возможностей, разделённых пробелами: "<command>=<feature-1> <feature-2>"
Запрос fetch может принимать следующие аргументы:
want <oid> Indicates to the server an object which the client wants to retrieve. Wants can be anything and are not limited to advertised objects.
have <oid> Indicates to the server an object which the client has locally. This allows the server to make a packfile which only contains the objects that the client needs. Multiple 'have' lines can be supplied.
done Indicates to the server that negotiation should terminate (or not even begin if performing a clone) and that the server should use the information supplied in the request to construct the packfile.
thin-pack Request that a thin pack be sent, which is a pack with deltas which reference base objects not contained within the pack (but are known to exist at the receiving end). This can reduce the network traffic significantly, but it requires the receiving end to know how to "thicken" these packs by adding the missing bases to the pack.
no-progress Request that progress information that would normally be sent on side-band channel 2, during the packfile transfer, should not be sent. However, the side-band channel 3 is still used for error responses.
include-tag Request that annotated tags should be sent if the objects they point to are being sent.
ofs-delta Indicate that the client understands PACKv2 with delta referring to its base by position in pack rather than by an oid. That is, they can read OBJ_OFS_DELTA (aka type 6) in a packfile.
Если объявлена возможность shallow, в запрос клиента можно включить следующие аргументы, а ответ сервера может дополнительно содержать раздел shallow-info, как поясняется ниже.
shallow <oid> A client must notify the server of all commits for which it only has shallow copies (meaning that it doesn't have the parents of a commit) by supplying a 'shallow <oid>' line for each such object so that the server is aware of the limitations of the client's history. This is so that the server is aware that the client may not have all objects reachable from such commits.
deepen <depth> Requests that the fetch/clone should be shallow having a commit depth of <depth> relative to the remote side.
deepen-relative Requests that the semantics of the "deepen" command be changed to indicate that the depth requested is relative to the client's current shallow boundary, instead of relative to the requested commits.
deepen-since <timestamp> Requests that the shallow clone/fetch should be cut at a specific time, instead of depth. Internally it's equivalent to doing "git rev-list --max-age=<timestamp>". Cannot be used with "deepen".
deepen-not <rev> Requests that the shallow clone/fetch should be cut at a specific revision specified by '<rev>', instead of a depth. Internally it's equivalent of doing "git rev-list --not <rev>". Cannot be used with "deepen", but can be used with "deepen-since".
Если объявлена возможность filter, в запрос клиента можно включить следующий аргумент:
filter <filter-spec> Request that various objects from the packfile be omitted using one of several filtering techniques. These are intended for use with partial clone and partial fetch operations. See `rev-list` for possible "filter-spec" values. When communicating with other processes, senders SHOULD translate scaled integers (e.g. "1k") into a fully-expanded form (e.g. "1024") to aid interoperability with older receivers that may not understand newly-invented scaling suffixes. However, receivers SHOULD accept the following suffixes: 'k', 'm', and 'g' for 1024, 1048576, and 1073741824, respectively.
Если объявлена возможность ref-in-want, в запрос клиента можно включить следующий аргумент, а ответ сервера может дополнительно содержать раздел wanted-refs, как поясняется ниже.
want-ref <ref> Indicates to the server that the client wants to retrieve a particular ref, where <ref> is the full name of a ref on the server. It is a protocol error to send want-ref for the same ref more than once.
Если объявлена возможность sideband-all, в запрос клиента можно включить следующий аргумент:
sideband-all Instruct the server to send the whole response multiplexed, not just the packfile section. All non-flush and non-delim PKT-LINE in the response (not only in the packfile section) will then start with a byte indicating its sideband (1, 2, or 3), and the server may send "0005\2" (a PKT-LINE of sideband 2 with no payload) as a keepalive packet.
Если объявлена возможность packfile-uris, в запрос клиента можно включить следующий аргумент, а ответ сервера может дополнительно содержать раздел packfile-uris, как поясняется ниже. Обратите внимание: серверу можно отправить не более одной строки packfile-uris.
packfile-uris <comma-separated-list-of-protocols> Indicates to the server that the client is willing to receive URIs of any of the given protocols in place of objects in the sent packfile. Before performing the connectivity check, the client should download from all given URIs. Currently, the protocols supported are "http" and "https".
Если объявлена возможность wait-for-done, в запрос клиента можно включить следующий аргумент.
wait-for-done Indicates to the server that it should never send "ready", but should wait for the client to say "done" before sending the packfile.
Ответ fetch разделён на несколько секций пакетами-разделителями (0001); каждая секция начинается с заголовка. Большинство секций отправляются только вместе с packfile.
output = acknowledgements flush-pkt | [acknowledgments delim-pkt] [shallow-info delim-pkt] [wanted-refs delim-pkt] [packfile-uris delim-pkt] packfile flush-pkt
acknowledgments = PKT-LINE("acknowledgments" LF)
(nak | *ack)
(ready)
ready = PKT-LINE("ready" LF)
nak = PKT-LINE("NAK" LF)
ack = PKT-LINE("ACK" SP obj-id LF) shallow-info = PKT-LINE("shallow-info" LF)
*PKT-LINE((shallow | unshallow) LF)
shallow = "shallow" SP obj-id
unshallow = "unshallow" SP obj-id wanted-refs = PKT-LINE("wanted-refs" LF)
*PKT-LINE(wanted-ref LF)
wanted-ref = obj-id SP refname packfile-uris = PKT-LINE("packfile-uris" LF) *packfile-uri
packfile-uri = PKT-LINE(40*(HEXDIGIT) SP *%x20-ff LF) packfile = PKT-LINE("packfile" LF)
*PKT-LINE(%x01-03 *%x00-ff) acknowledgments section * If the client determines that it is finished with negotiations by sending a "done" line (thus requiring the server to send a packfile), the acknowledgments sections MUST be omitted from the server's response.
-
Всегда начинается с заголовка секции "acknowledgments"
-
Сервер ответит "NAK", если ни один из идентификаторов объектов, отправленных в строках have, не является общим.
-
Сервер ответит "ACK obj-id" для каждого общего идентификатора объекта, отправленного в строках have.
-
Ответ не может содержать одновременно строки "ACK" и строку "NAK".
-
Сервер отправит строку "ready", указывающую, что он нашёл подходящую общую базу и готов создать и отправить packfile (он будет находиться в секции packfile того же ответа).
-
Если сервер нашёл подходящую точку отсечения и решил отправить строку "ready", он может (в целях оптимизации) опустить любые строки "ACK", которые иначе отправил бы в ответе. Это возможно потому, что сервер уже определил объекты, которые собирается отправить клиенту, и дальнейшее согласование не требуется.
shallow-info section * If the client has requested a shallow fetch/clone, a shallow client requests a fetch or the server is shallow then the server's response may include a shallow-info section. The shallow-info section will be included if (due to one of the above conditions) the server needs to inform the client of any shallow boundaries or adjustments to the clients already existing shallow boundaries.
-
Всегда начинается с заголовка секции "shallow-info"
-
Если запрошена положительная глубина, сервер вычислит набор коммитов, глубина которых не превышает заданную.
-
Для каждого коммита, родители которого не будут отправлены в следующем packfile, сервер отправляет строку "shallow obj-id".
-
Для каждого коммита, который клиент обозначил как неглубокий, но который перестал быть неглубоким в результате fetch (поскольку его родители отправляются в следующем packfile), сервер отправляет строку "unshallow obj-id".
-
Сервер НЕ ДОЛЖЕН отправлять строки "unshallow" для объектов, которые клиент не обозначил как неглубокие в запросе.
wanted-refs section * This section is only included if the client has requested a ref using a 'want-ref' line and if a packfile section is also included in the response.
-
Всегда начинается с заголовка секции "wanted-refs".
-
Для каждой ссылки, запрошенной с помощью строк
want-ref, сервер отправит список ссылок ("<oid> <refname>"). -
Сервер НЕ ДОЛЖЕН отправлять ссылки, не запрошенные с помощью строк
want-ref.packfile-uris section * This section is only included if the client sent 'packfile-uris' and the server has at least one such URI to send.
-
Всегда начинается с заголовка секции "packfile-uris".
-
Для каждого URI сервер отправляет хеш содержимого pack (как возвращает git index-pack), за которым следует URI.
-
Длина хешей составляет 40 шестнадцатеричных символов. При переходе Git на новый алгоритм хеширования это может потребовать обновления. (Значение должно совпадать с выводом index-pack после "pack\t" или "keep\t".)
packfile section * This section is only included if the client has sent 'want' lines in its request and either requested that no more negotiation be done by sending 'done' or if the server has decided it has found a sufficient cut point to produce a packfile.
-
Всегда начинается с заголовка секции "packfile"
-
Передача packfile начинается сразу после заголовка секции
-
Передача данных packfile всегда мультиплексируется с использованием той же семантики, что и у возможности
side-band-64kиз протокола версии 1. Это означает, что каждый пакет в потоке данных packfile состоит из начальной 4-байтовой длины pkt-line (типичной для формата pkt-line), за которой следует 1-байтовый код потока, а затем собственно данные.The stream code can be one of: 1 - pack data 2 - progress messages 3 - fatal error message just before stream aborts
server-option
Если эта возможность объявлена, в запрос можно включить любое количество параметров, специфичных для сервера. Для этого каждый параметр передаётся отдельной строкой возможности "server-option=<option>" в секции capability-list запроса.
Передаваемые параметры не должны содержать символ NUL или LF.
object-format
Сервер может объявить возможность object-format со значением X (в форме object-format=X), чтобы сообщить клиенту, что сервер умеет работать с объектами, использующими алгоритм хеширования X. Если значение не указано, предполагается, что сервер поддерживает только SHA-1. Если клиент хочет использовать алгоритм хеширования, отличный от SHA-1, ему следует указать строку object-format.
session-id=<session-id>
Сервер может объявить идентификатор сеанса, который можно использовать для идентификации этого процесса в нескольких запросах. Клиент также может передать серверу собственный идентификатор сеанса.
Идентификаторы сеансов должны быть уникальными для каждого процесса. Они должны помещаться в строку packet-line и не должны содержать непечатных символов или пробельных символов. Текущая реализация использует идентификаторы сеансов trace2 (подробности см. в api-trace2), однако это может измениться, поэтому пользователям идентификатора сеанса не следует полагаться на это.
object-info
object-info — команда для получения информации об одном или нескольких объектах. Её основное назначение — позволить клиенту принимать решения на основе этой информации, не загружая объекты целиком. В настоящее время поддерживается только информация о размере объекта.
Запрос object-info принимает следующие аргументы:
size Requests size information to be returned for each listed object id.
oid <oid> Indicates to the server an object which the client wants to obtain information for.
Ответ object-info представляет собой список запрошенных идентификаторов объектов и соответствующей запрошенной информации, разделённых одиночным пробелом.
output = info flush-pkt
info = PKT-LINE(attrs) LF)
*PKT-LINE(obj-info LF) attrs = attr | attrs SP attrs
attr = "size"
obj-info = obj-id SP obj-size
bundle-uri
Если объявлена возможность bundle-uri, сервер поддерживает команду ‘bundle-uri’.
В настоящее время возможность объявляется без значения (то есть не "bundle-uri=somevalue"); в будущем для поддержки расширений на уровне команды может быть добавлено значение. Клиенты ДОЛЖНЫ игнорировать любые неизвестные значения возможностей и продолжать диалог 'bundle-uri`, используя поддерживаемые ими возможности.
Команда bundle-uri предназначена для выполнения перед fetch, чтобы получить URI файлов bundle (см. git-bundle[1]) для «предварительной загрузки» и передачи информации последующей команде fetch.
Клиент МОЖЕТ выполнить bundle-uri до или после любой другой допустимой команды. Предполагается, что для клиента полезно выполнить её после ls-refs и до fetch, однако её МОЖНО выполнить в любой момент диалога.
ОБСУЖДЕНИЕ bundle-uri
Эта возможность предназначена для оптимизации расхода ресурсов сервера в типичном случае: вместо получения очень большого PACK во время git-clone[1] выполняется небольшая инкрементальная загрузка.
Она также позволяет серверам эффективнее использовать кеширование совместно с uploadpack.packObjectsHook (см. git-config[1]).
При этом новые клонирования или загрузки выполняют более предсказуемое и распространённое согласование относительно вершин недавно созданных файлов *.bundle. Серверы могут даже заранее генерировать результаты таких согласований для uploadpack.packObjectsHook по мере поступления новых отправок.
Один из способов использования этих bundle на сервере — предполагать, что при свежем клонировании будет загружен известный bundle, а затем состояние репозитория будет приведено к актуальному с помощью вершин ссылок, содержащихся в этом bundle (или наборах bundle).
ПРОТОКОЛ bundle-uri
Запрос bundle-uri не принимает аргументов и, как отмечено выше, в настоящее время не объявляет значение возможности. В будущем могут быть добавлены и то и другое.
Когда клиент отправляет запрос command=bundle-uri, ответ представляет собой список пар «ключ-значение», передаваемых в виде строк packet-line со значением <key>=<value>. Каждый <key> следует трактовать как ключ конфигурации из пространства имён bundle.* для формирования списка bundle. Эти ключи сгруппированы по подразделу bundle.<id>.; каждый ключ, относящийся к заданному <id>, добавляет атрибуты к bundle, определяемому этим <id>. Подробное описание этих ключей и интерпретации их значений клиентом Git см. в git-config[1].
Клиенты ДОЛЖНЫ анализировать строки в соответствии с описанным выше форматом; строки, не соответствующие формату, СЛЕДУЕТ отбрасывать. В таком случае пользователь МОЖЕТ получить предупреждение.
ОЖИДАНИЯ К КЛИЕНТУ И СЕРВЕРУ bundle-uri
- СОДЕРЖИМОЕ URI
-
Содержимое объявленных URI ДОЛЖНО относиться к одному из двух типов.
Объявленный URI может содержать файл bundle, который примет
gitbundleverify. То есть он ДОЛЖЕН содержать одну или несколько вершин ссылок, используемых клиентом, ДОЛЖЕН указывать предварительные требования (если они есть) с помощью стандартных префиксов "-", а также ДОЛЖЕН указывать "object-format", если применимо.Вместо этого объявленный URI может содержать текстовый файл, который примет
gitconfiglist(с параметром--file). Пары «ключ-значение» в этом списке относятся к пространству имёнbundle.*(см. git-config[1]). - ВОССТАНОВЛЕНИЕ КЛИЕНТА bundle-uri ПОСЛЕ ОШИБОК
-
Клиент прежде всего ДОЛЖЕН корректно обрабатывать ошибки и переходить к резервному варианту, будь то ошибка из-за отсутствующих или некорректных данных в URI bundle, из-за того, что клиент не способен, например, понять и полностью разобрать заголовки bundle и связи предварительных требований, или по какой-либо другой причине.
Операторы серверов могут уверенно включать "bundle-uri" и не беспокоиться о том, что, например, сбой CDN приведёт к серьёзным ошибкам при клонировании или загрузке. Даже если bundle сервера неполны или каким-либо образом повреждены, клиент всё равно должен получить работоспособный репозиторий — так же, как если бы он решил не использовать это расширение протокола.
При любом дальнейшем обсуждении взаимодействия клиента и сервера НЕОБХОДИМО учитывать это.
- ОТ СЕРВЕРА К КЛИЕНТУ bundle-uri
-
Порядок возвращаемых URI bundle не имеет значения. Клиенты ДОЛЖНЫ анализировать их заголовки, чтобы определить содержащиеся в них OID и предварительные требования. Клиент ДОЛЖЕН считать содержимое самих bundle и их заголовки окончательным источником достоверной информации.
Сервер МОЖЕТ даже вернуть bundle, не имеющие прямого отношения к клонируемому репозиторию (случайно или в результате намеренно «хитрой» конфигурации), и ожидать, что клиент сам выберет нужные ему данные из этих bundle или решит не использовать их.
- ОТ КЛИЕНТА К СЕРВЕРУ bundle-uri
-
КлиентУ СЛЕДУЕТ передавать вершины ссылок, найденные в заголовках bundle, в виде строк
haveв любом последующем запросеfetch. Клиент МОЖЕТ также полностью проигнорировать bundle, если сочтёт это предпочтительным, например если bundle невозможно загрузить или клиенту не нравятся найденные в них вершины. - КОГДА ДЛЯ ОБЪЯВЛЕННЫХ BUNDLE НЕ ТРЕБУЕТСЯ ДАЛЬНЕЙШЕЕ СОГЛАСОВАНИЕ
-
Если после выполнения
bundle-uriиls-refsи получения заголовков bundle клиент обнаруживает, что нужные ему вершины ссылок можно получить целиком из объявленных bundle, он МОЖЕТ отключиться от сервера Git. Результаты такогоcloneилиfetchдолжны быть неотличимы от состояния, достигнутого без использования bundle-uri. - РАННЕЕ ОТКЛЮЧЕНИЕ КЛИЕНТА И ВОССТАНОВЛЕНИЕ ПОСЛЕ ОШИБОК
-
Клиент МОЖЕТ отключиться досрочно, пока bundle ещё загружаются (после получения и разбора их заголовков). В этом случае клиент ДОЛЖЕН корректно обработать любые ошибки, связанные с завершением загрузки и проверкой bundle.
То есть клиенту может потребоваться подключиться повторно и выполнить команду
fetch, а также, возможно, полностью отказаться от использованияbundle-uri.Такое поведение «МОЖЕТ» оговорено именно в этой форме (а не как «СЛЕДУЕТ») исходя из предположения, что сервер, объявляющий URI bundle, скорее всего обслуживает относительно большой репозиторий и указывает URI, которые с большой вероятностью работают. Клиент МОЖЕТ, например, оценить размер полезной нагрузки bundle и использовать его как эвристику, чтобы определить, оправдано ли раннее отключение, если может потребоваться перейти к полному диалогу "fetch".
- КОГДА ДЛЯ ОБЪЯВЛЕННЫХ BUNDLE ТРЕБУЕТСЯ ДАЛЬНЕЙШЕЕ СОГЛАСОВАНИЕ
-
Клиенту СЛЕДУЕТ начать согласование PACK с сервером с помощью команды "fetch", используя OID-вершины, найденные в объявленных bundle, даже если загрузка этих bundle ещё продолжается.
Это позволяет агрессивно отключаться от интерактивного диалога с сервером на раннем этапе. Клиент без дополнительной проверки доверяет объявленным OID-вершинам и передаёт их в виде строк
have, а затем запрашивает нужные ему вершины (обычно из объявления "ls-refs") с помощью строкwant. После этого сервер вычисляет (предположительно небольшой) PACK с ожидаемой разницей между вершинами из bundle и запрошенными данными.Единственное соединение, которое клиенту затем требуется поддерживать активным, — соединение для параллельной загрузки статических bundle. После получения bundle и инкрементального PACK их следует распаковать и проверить. Любые ошибки на этом этапе следует корректно обработать, см. выше.
ВОЗМОЖНОСТИ ПРОТОКОЛА bundle-uri
Клиент формирует список bundle из пар <key>=<value>, предоставленных сервером. Эти пары относятся к пространству имён bundle.*, описанному в git-config[1]. В этом разделе рассматриваются некоторые из этих ключей и описываются действия, которые клиент выполняет в ответ на полученную информацию.
В частности, ключ bundle.version задаёт целочисленное значение. В настоящий момент принимается только значение 1, однако, если клиент увидит здесь неожиданное значение, он ДОЛЖЕН игнорировать список bundle.
Если значение bundle.version распознано, клиент МОЖЕТ игнорировать все остальные неизвестные ключи. Сервер гарантирует совместимость со старыми клиентами, хотя новые клиенты могут эффективнее использовать дополнительные ключи для сокращения объёма загрузок.
Любое обратно несовместимое добавление пар «ключ-значение» до URI будет сопровождаться новым значением или значениями bundle.version в самом объявлении возможности bundle-uri и/или новыми аргументами будущих запросов bundle-uri.
Некоторые примеры пар «ключ-значение», которые пока не реализованы, но могут быть реализованы в будущем:
-
Объявление "hash=<val>" или "size=<bytes>" для указания ожидаемого хеша или размера файла bundle.
-
Объявление того, что один или несколько файлов bundle совпадают (например, чтобы клиенты могли выбирать один из N файлов по схеме round-robin или иным способом).
-
Сокращённая форма "oid=<OID>" и "prerequisite=<OID>" для представления распространённого случая bundle с одной вершиной без предварительных требований или с одной вершиной и одним предварительным требованием.
Это позволило бы оптимизировать распространённый сценарий, когда серверы хотят предоставить один «большой bundle», содержащий только их основную ветку, и/или инкрементальные обновления для неё.
Получив такой ответ, клиент МОЖЕТ предположить, что ему не нужно получать заголовок bundle по указанному URI, и тем самым сэкономить себе и серверам запросы, необходимые для проверки заголовков этого bundle или этих bundle.
promisor-remote=<pr-info>
Сервер может сообщить клиенту об используемых им или известных ему удалённых репозиториях-обещателях, которые клиент может захотеть использовать вместо этого репозитория. В этом случае <pr-info> должно иметь следующий формат:
pr-info = pr-fields | pr-info ";" pr-fields
pr-fields = pr-field | pr-fields "," pr-field
pr-field = field-name "=" field-value
где все field-name и field-value в заданном pr-fields являются именами полей и их значениями, относящимися к одному удалённому репозиторию-обещателю. Один и тот же field-name НЕ ДОЛЖЕН встречаться более одного раза в заданном pr-fields.
Сервер ОБЯЗАН указать имена полей «name» и «url» вместе с соответствующими значениями полей — именем действительного удалённого репозитория и его URL — в каждом pr-fields. Поля «name» и «url» ДОЛЖНЫ располагаться первыми в каждом pr-fields именно в таком порядке.
После этих обязательных полей сервер МОЖЕТ указать следующие необязательные поля в любом порядке:
-
partialCloneFilter -
Спецификация фильтрации для удалённого репозитория. Она соответствует параметру конфигурации «remote.<name>.partialCloneFilter». Клиенты могут использовать её, чтобы определить, совместима ли стратегия фильтрации удалённого репозитория с их потребностями (например, проверить, используют ли оба репозитория «blob:none»). Кроме того, её можно использовать с параметром
--filter=autoкоманды git-clone[1]. При использовании этого параметра спецификация фильтрации клонируемого репозитория будет автоматически вычислена путём объединения спецификаций фильтрации принятых клиентом удалённых репозиториев-обещателей. -
token -
Токен аутентификации, который клиенты могут использовать при подключении к удалённому репозиторию. Он соответствует параметру конфигурации «remote.<name>.token».
На данный момент протокол не определяет других полей. Имена полей чувствительны к регистру и ДОЛЖНЫ передаваться точно в указанном выше виде. Клиенты ОБЯЗАНЫ игнорировать неизвестные им поля, чтобы обеспечить возможность будущих расширений протокола.
Клиент может использовать информацию, переданную в этих полях, чтобы решить, принимать ли объявленный удалённый репозиторий-обещатель. Кроме того, клиент можно настроить так, чтобы он сохранял значения этих полей или использовал их для автоматической настройки репозитория (см. «promisor.storeFields» в git-config[1] и --filter=auto в git-clone[1]).
Значения полей ДОЛЖНЫ быть закодированы с помощью URL-кодирования.
Если клиент решит использовать один или несколько объявленных сервером удалённых репозиториев-обещателей, он может ответить строкой «promisor-remote=<pr-names>», где <pr-names> должно иметь следующий формат:
pr-names = pr-name | pr-names ";" pr-name
где pr-name — это закодированное с помощью URL-кодирования имя объявленного сервером удалённого репозитория-обещателя, который клиент принимает.
При попытке получить отсутствующие объекты клиент будет обращаться к принятым удалённым репозиториям-обещателям раньше, чем к другим настроенным удалённым репозиториям-обещателям.
Обратите внимание: везде в этом документе символы ; и , ДОЛЖНЫ кодироваться, если они встречаются в pr-name или field-value.
Если серверу неизвестен подходящий для клиента удалённый репозиторий-обещатель или он предпочитает, чтобы клиент не использовал ни один из используемых или известных серверу удалённых репозиториев-обещателей, серверу не следует объявлять возможность «promisor-remote».
В этом случае, а также если клиент не хочет использовать ни один из объявленных сервером удалённых репозиториев-обещателей, клиенту не следует объявлять возможность «promisor-remote» в своём ответе.
На стороне сервера параметры конфигурации «promisor.advertise» и «promisor.sendFields» позволяют управлять передаваемой информацией. На стороне клиента параметр конфигурации «promisor.acceptFromServer» позволяет управлять тем, какие данные он принимает, а параметр «promisor.storeFields» — тем, какие данные он сохраняет. Дополнительные сведения об этих параметрах конфигурации см. в документации git-config[1].
Обратите внимание: в будущем было бы полезно использовать возможность протокола «promisor-remote» на сервере при ответе на git fetch или git clone, чтобы сообщать о более тесно связанных удалённых репозиториях, которые клиент может использовать в качестве удалённых репозиториев-обещателей вместо этого репозитория и из которых он сможет отложенно получать объекты. Для этого серверу потребуется не включать в ответ объекты, доступные в принятых клиентом более тесно связанных удалённых репозиториях. Однако эта возможность ещё не реализована. Поэтому пока возможность «promisor-remote» полезна только в том случае, если сервер сообщает о некоторых удалённых репозиториях-обещателях, из которых он уже получает объекты.
gitprotocol-v2
© 2005–2026 Linus Torvalds and others
Licensed under the GNU General Public License version 2.
https://git-scm.com/docs/gitprotocol-v2