Spec-Zone.ru › Git

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, который примет git bundle verify. То есть он ДОЛЖЕН содержать одну или несколько вершин ссылок, используемых клиентом, ДОЛЖЕН указывать предварительные требования (если они есть) с помощью стандартных префиксов "-", а также ДОЛЖЕН указывать "object-format", если применимо.

Вместо этого объявленный URI может содержать текстовый файл, который примет git config list (с параметром --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

Spec-Zone.ru

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