Spec-Zone.ru › Git

gitprotocol-pack

Название

gitprotocol-pack — передача пакетов по сети

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

<over-the-wire-protocol>

Описание

Git поддерживает передачу данных в файлах пакетов через транспортные протоколы ssh://, git://, http:// и file://. Существуют два набора протоколов: один для отправки данных с клиента на сервер, другой для получения данных с сервера на клиент. Три транспортных протокола (ssh, git, file) используют один и тот же протокол для передачи данных. Описание протокола http приведено в gitprotocol-http[5].

В канонической реализации Git на стороне сервера для получения данных запускаются процессы upload-pack, а на стороне клиента — fetch-pack; для отправки данных запускаются receive-pack на сервере и send-pack на клиенте. Протокол позволяет серверу сообщить клиенту, что сейчас находится на сервере, после чего обе стороны согласовывают минимальный объём данных, который необходимо отправить, чтобы полностью обновить один или другой репозиторий.

Формат pkt-line

Приведённые ниже описания основаны на формате pkt-line, описанном в gitprotocol-common[5]. Когда грамматика указывает PKT-LINE(...), если не указано иное, применяются обычные правила LF для pkt-line: ОТПРАВИТЕЛЬ ДОЛЖЕН включать LF, но ПОЛУЧАТЕЛЬ НЕ ДОЛЖЕН жаловаться, если он отсутствует.

Пакет ошибки — это специальный pkt-line, содержащий строку ошибки.

  error-line     =  PKT-LINE("ERR" SP explanation-text)

Во всех местах протокола, где ожидается PKT-LINE(...), МОЖЕТ быть отправлен пакет ошибки. После отправки этого пакета клиентом или сервером процесс передачи данных, определённый в этом протоколе, завершается.

Транспортные протоколы

Протокол передачи пакетов может запускаться через три транспортных протокола.

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

При использовании транспорта SSH клиент просто запускает процесс upload-pack или receive-pack на сервере через протокол SSH, а затем взаимодействует с запущенным процессом через SSH-соединение.

Транспорт file:// запускает процесс upload-pack или receive-pack локально и взаимодействует с ним через канал.

Дополнительные параметры

Протокол предоставляет клиентам механизм отправки дополнительной информации серверу в первом сообщении. Эти параметры называются «дополнительными параметрами» и поддерживаются протоколами Git, SSH и HTTP.

Каждый дополнительный параметр имеет вид <key>=<value> или <key>.

Серверы, получающие такие дополнительные параметры, ДОЛЖНЫ игнорировать все нераспознанные ключи. В настоящее время распознаётся только дополнительный параметр «version» со значением 1 или 2. Дополнительные сведения о версии протокола 2 см. в gitprotocol-v2[5].

Транспорт Git

Транспорт Git начинается с отправки по сети команды и репозитория в формате pkt-line, после чего следует нулевой байт и параметр имени узла, завершающийся нулевым байтом.

0033git-upload-pack /project.git\0host=myserver.com\0

Транспорт может передавать дополнительные параметры, добавив ещё один нулевой байт, а затем одну или несколько строк, завершающихся нулевым байтом:

003egit-upload-pack /project.git\0host=myserver.com\0\0version=1\0
git-proto-request = request-command SP pathname NUL
      [ host-parameter NUL ] [ NUL extra-parameters ]
request-command   = "git-upload-pack" / "git-receive-pack" /
      "git-upload-archive"   ; case sensitive
pathname          = *( %x01-ff ) ; exclude NUL
host-parameter    = "host=" hostname [ ":" port ]
extra-parameters  = 1*extra-parameter
extra-parameter   = 1*( %x01-ff ) NUL

Параметр host используется для виртуального хостинга на основе имени git-daemon. См. параметр --interpolated-path команды git daemon и символы формата %H/%CH.

В общих чертах клиент Git подключается к процессу upload-pack на стороне сервера через протокол Git следующим образом:

$ echo -e -n \
  "003agit-upload-pack /schacon/gitbook.git\0host=example.com\0" |
  nc -v example.com 9418

Транспорт SSH

Запуск процессов upload-pack или receive-pack через SSH выполняет бинарный файл на сервере посредством удалённого выполнения SSH. По сути, это эквивалентно выполнению следующей команды:

$ ssh git.example.com "git-upload-pack '/project.git'"

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

В URI формата ssh:// путь является абсолютным, поэтому / после имени узла (или номера порта) передаётся как аргумент, который затем считывается удалённым git-upload-pack без изменений; таким образом, это фактически абсолютный путь в удалённой файловой системе.

   git clone ssh://user@example.com/project.git
  |
  v
ssh user@example.com "git-upload-pack '/project.git'"

В URI формата «user@host:path» путь задаётся относительно домашнего каталога пользователя, поскольку клиент Git выполняет следующую команду:

   git clone user@example.com:project.git
    |
    v
ssh user@example.com "git-upload-pack 'project.git'"

Исключение составляет случай, когда используется ~: в этом случае команда выполняется без начального /.

   ssh://user@example.com/~alice/project.git,
    |
    v
ssh user@example.com "git-upload-pack '~alice/project.git'"

В зависимости от значения переменной конфигурации protocol.version Git может попытаться передать дополнительные параметры в виде строки, разделённой двоеточиями, в переменной окружения GIT_PROTOCOL. Это делается только в том случае, если переменная конфигурации ssh.variant указывает, что команда ssh поддерживает передачу переменных окружения в качестве аргумента.

Здесь важно помнить следующее:

  • «Имя команды» записывается через дефис (например, git-upload-pack), но клиент может переопределить его;

  • Путь к репозиторию всегда заключается в одинарные кавычки.

Получение данных с сервера

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

Обнаружение ссылок

При первоначальном подключении клиента сервер сразу же отвечает номером версии (если в качестве дополнительного параметра передано «version=1») и списком всех имеющихся у него ссылок (всех веток и тегов), а также именами объектов, на которые в данный момент указывает каждая ссылка.

 $ echo -e -n "0045git-upload-pack /schacon/gitbook.git\0host=example.com\0\0version=1\0" |
    nc -v example.com 9418
 000eversion 1
 00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack
side-band side-band-64k ofs-delta shallow no-progress include-tag
 00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
 003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master
 003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9
 003c525128480b96c89e6418b1e40909bf6c5b2d580f refs/tags/v1.0
 003fe92df48743b7bc7d26bcaabfddde0a1e20cae47c refs/tags/v1.0^{}
 0000

В ответе передаётся поток pkt-line, описывающий каждую ссылку и её текущее значение. Поток ДОЛЖЕН быть отсортирован по имени в соответствии с порядком локали C.

Если HEAD является допустимой ссылкой, HEAD ДОЛЖЕН быть первой объявленной ссылкой. Если HEAD не является допустимой ссылкой, HEAD НЕ ДОЛЖЕН присутствовать в списке объявлений, но другие ссылки могут быть включены.

Поток ДОЛЖЕН содержать объявления возможностей после нулевого байта в первой ссылке. Если развёрнутое значение ссылки (то есть «ref^{}») представлено, оно ДОЛЖНО идти непосредственно после самой ссылки. Совместимый сервер ДОЛЖЕН разворачивать ссылку, если она является аннотированным тегом.

  advertised-refs  =  *1("version 1")
                      (no-refs / list-of-refs)
                      *shallow
                      flush-pkt

  no-refs          =  PKT-LINE(zero-id SP "capabilities^{}"
                      NUL capability-list)

  list-of-refs     =  first-ref *other-ref
  first-ref        =  PKT-LINE(obj-id SP refname
                      NUL capability-list)

  other-ref        =  PKT-LINE(other-tip / other-peeled)
  other-tip        =  obj-id SP refname
  other-peeled     =  obj-id SP refname "^{}"

  shallow          =  PKT-LINE("shallow" SP obj-id)

  capability-list  =  capability *(SP capability)
  capability       =  1*(LC_ALPHA / DIGIT / "-" / "_")
  LC_ALPHA         =  %x61-7A

Сервер и клиент ДОЛЖНЫ использовать строчные буквы для obj-id; обе стороны ДОЛЖНЫ считать регистр символов в obj-id незначимым.

Список разрешённых возможностей сервера и их описания см. в protocol-capabilities.txt.

Согласование файла пакета

После обнаружения ссылок и возможностей клиент может завершить соединение, отправив flush-pkt, чтобы сообщить серверу, что тот может корректно завершить работу и отключиться, если клиенту не нужны данные пакета. Это может произойти при выполнении команды ls-remote, а также если клиент уже обновлён.

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

  upload-request    =  want-list
                       *shallow-line
                       *1depth-request
                       [filter-request]
                       flush-pkt

  want-list         =  first-want
                       *additional-want

  shallow-line      =  PKT-LINE("shallow" SP obj-id)

  depth-request     =  PKT-LINE("deepen" SP depth) /
                       PKT-LINE("deepen-since" SP timestamp) /
                       PKT-LINE("deepen-not" SP ref)

  first-want        =  PKT-LINE("want" SP obj-id SP capability-list)
  additional-want   =  PKT-LINE("want" SP obj-id)

  depth             =  1*DIGIT

  filter-request    =  PKT-LINE("filter" SP filter-spec)

Клиенты ДОЛЖНЫ отправить все нужные им obj-id из этапа обнаружения ссылок в виде строк want. Клиенты ДОЛЖНЫ отправить в теле запроса как минимум одну команду want. Клиенты НЕ ДОЛЖНЫ указывать в команде want obj-id, отсутствовавший в ответе, полученном при обнаружении ссылок.

Клиент ДОЛЖЕН передать все obj-id, для которых у него имеются только неглубокие копии (то есть у него нет родительских коммитов), в виде строк shallow, чтобы сервер знал об ограничениях истории клиента.

Теперь клиент отправляет максимальную глубину истории коммитов для этой операции — количество коммитов от вершины истории, которое он хочет получить, если оно задано, — в виде строки deepen. Глубина 0 равносильна отсутствию запроса глубины. Клиент не хочет получать коммиты за пределами этой глубины и объекты, необходимые только для завершения этих коммитов. Коммиты, родители которых не получены в результате операции, считаются неглубокими и помечаются сервером соответствующим образом. Эта информация передаётся клиенту на следующем этапе.

Клиент может дополнительно запросить у pack-objects исключение различных объектов из файла пакета, используя один из нескольких способов фильтрации. Эти способы предназначены для частичного клонирования и частичного получения данных. Объект, не соответствующий значению filter-spec, исключается, если только он явно не запрошен в строке want. Возможные значения filter-spec см. в rev-list.

После передачи всех want’s and 'shallow’s (and optional 'deepen) клиенты ДОЛЖНЫ отправить flush-pkt, чтобы сообщить серверу, что отправка списка завершена.

В противном случае, если клиент запросил положительную глубину, сервер определяет, какие коммиты будут неглубокими, и отправляет эту информацию клиенту. Если клиент не запрашивал положительную глубину, этот этап пропускается.

  shallow-update   =  *shallow-line
                      *unshallow-line
                      flush-pkt

  shallow-line     =  PKT-LINE("shallow" SP obj-id)

  unshallow-line   =  PKT-LINE("unshallow" SP obj-id)

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

Сервер записывает строки shallow для каждого коммита, родители которого не будут отправлены. Сервер записывает строку unshallow для каждого коммита, который клиент указал как неглубокий, но который перестал быть неглубоким при текущей запрошенной глубине (то есть теперь будут отправлены его родители). Сервер НЕ ДОЛЖЕН помечать как неглубокий любой объект, который клиент не указал как неглубокий.

Теперь клиент отправляет список имеющихся у него obj-id в виде строк have, чтобы сервер мог создать файл пакета, содержащий только нужные клиенту объекты. В режиме multi_ack каноническая реализация отправляет за раз до 32 таких строк, а затем отправляет flush-pkt. Каноническая реализация сразу же переходит к следующей группе и отправляет следующие 32 строки, так что в каждый момент времени в передаче находится блок из 32 строк.

  upload-haves      =  have-list
                       compute-end

  have-list         =  *have-line
  have-line         =  PKT-LINE("have" SP obj-id)
  compute-end       =  flush-pkt / PKT-LINE("done")

Если сервер считывает строки have, он отвечает ACK для всех указанных клиентом obj-id, которые также есть у сервера. Сервер отправляет ACK для obj-id по-разному в зависимости от выбранного клиентом режима подтверждения.

В режиме multi_ack:

  • сервер отправляет ACK obj-id continue для всех общих коммитов.

  • обнаружив приемлемый общий базовый коммит и подготовившись к созданию файла пакета, сервер без разбора отправляет клиенту ACK для всех obj-id have.

  • затем сервер отправляет NAK и ожидает от клиента следующего ответа — либо done, либо ещё одного списка строк have.

В режиме multi_ack_detailed:

  • сервер различает ACK, сообщающие о готовности к отправке данных, и отправляет для них строки ACK obj-id ready, а для обнаруженных общих коммитов — строки ACK obj-id common.

Без multi_ack и multi_ack_detailed:

  • upload-pack отправляет «ACK obj-id» для первого найденного общего объекта. После этого он ничего не сообщает, пока клиент не отправит ему «done».

  • upload-pack отправляет «NAK» при получении flush-pkt, если общий объект ещё не найден. Если общий объект найден и ACK уже отправлен, при получении flush-pkt сервер ничего не отправляет.

Получив достаточно ответов ACK, чтобы определить, что у сервера достаточно информации для эффективного создания файла пакета (в канонической реализации это определяется, когда получено достаточно ACK, чтобы пометить все оставшиеся элементы очереди --date-order как общие с сервером, либо когда очередь --date-order пуста), или решив прекратить попытки (в канонической реализации это определяется, когда клиент отправил 256 строк have, ни одна из которых не получила ACK от сервера — то есть общих объектов нет и серверу следует просто отправить все свои объекты), клиент отправляет команду done. Команда done сообщает серверу, что клиент готов получить данные файла пакета.

Однако ограничение в 256 включается в канонической реализации клиента только в том случае, если в предыдущем раунде был получен хотя бы один ответ «ACK %s continue». Это помогает убедиться, что перед окончательным прекращением попыток найден хотя бы один общий предок.

После считывания от клиента строки done сервер либо отправляет заключительный ACK obj-id, либо отправляет NAK. obj-id — это имя объекта последнего коммита, признанного общим. Сервер отправляет ACK после done только в том случае, если имеется хотя бы одна общая база и включён multi_ack или multi_ack_detailed. Если общая база не найдена, сервер всегда отправляет NAK после done.

Вместо ACK или NAK сервер может отправить сообщение об ошибке (например, если он не распознаёт объект в строке want, полученной от клиента).

Затем сервер начинает отправлять данные файла пакета.

  server-response = *ack_multi ack / nak
  ack_multi       = PKT-LINE("ACK" SP obj-id ack_status)
  ack_status      = "continue" / "common" / "ready"
  ack             = PKT-LINE("ACK" SP obj-id)
  nak             = PKT-LINE("NAK")

Простое клонирование может выглядеть так (без строк have):

   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
     side-band-64k ofs-delta\n
   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
   C: 0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
   C: 0032want 74730d410fcb6603ace96f1dc55ea6196122532d\n
   C: 0000
   C: 0009done\n

   S: 0008NAK\n
   S: [PACKFILE]

Ответ при инкрементальном обновлении (получении данных) может выглядеть так:

   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
     side-band-64k ofs-delta\n
   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
   C: 0000
   C: 0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
   C: [30 more have lines]
   C: 0032have 74730d410fcb6603ace96f1dc55ea6196122532d\n
   C: 0000

   S: 003aACK 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01 continue\n
   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d continue\n
   S: 0008NAK\n

   C: 0009done\n

   S: 0031ACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
   S: [PACKFILE]

Данные файла пакета

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

Описание формата самого файла пакета см. в gitformat-pack[5].

Если клиент указал возможности side-band или side-band-64k, сервер отправляет данные файла пакета с мультиплексированием.

Каждый пакет начинается с длины pkt-line, указывающей объём следующих данных, за которой следует один байт, задающий канал передачи следующих данных.

В режиме side-band он отправляет до 999 байт данных и 1 управляющий код, всего до 1000 байт в одном pkt-line. В режиме side-band-64k он отправляет до 65519 байт данных и 1 управляющий код, всего до 65520 байт в одном pkt-line.

Байт канала передачи принимает значение 1, 2 или 3. Канал передачи 1 содержит данные файла пакета, канал 2 используется для сведений о ходе выполнения, которые клиент обычно выводит в stderr, а канал 3 используется для сведений об ошибках.

Если возможность side-band не указана, сервер передаёт весь файл пакета без мультиплексирования.

Отправка данных на сервер

Для отправки данных на сервер запускается процесс receive-pack, который позволяет клиенту указать, какие ссылки нужно обновить, а затем отправить все данные, необходимые серверу для завершения обновления этих ссылок. После получения и проверки всех данных сервер обновляет ссылки в соответствии с указаниями клиента.

Аутентификация

Сам протокол не содержит механизмов аутентификации. Аутентификацию должен обеспечивать транспорт, например SSH, до запуска процесса receive-pack. Если для транспорта Git настроен receive-pack, эти репозитории будут доступны для записи всем, кто может подключиться к этому порту (9418), поскольку данный транспорт не использует аутентификацию.

Обнаружение ссылок

Этап обнаружения ссылок почти не отличается от аналогичного этапа в протоколе получения данных. Каждый obj-id и имя ссылки на сервере отправляются клиенту в формате packet-line, после чего передаётся flush-pkt. Единственное реальное отличие — список возможностей: возможны только значения report-status, report-status-v2, delete-refs, ofs-delta, atomic и push-options.

Запрос на обновление ссылок и передача файла пакета

Узнав текущее состояние ссылок на сервере, клиент может отправить список запросов на их обновление. Для каждой ссылки на сервере, которую он хочет обновить, клиент отправляет строку с текущим obj-id на сервере, obj-id, на который клиент хочет её изменить, и именем ссылки.

После этого списка передаётся flush-pkt.

  update-requests   =  *shallow ( command-list | push-cert )

  shallow           =  PKT-LINE("shallow" SP obj-id)

  command-list      =  PKT-LINE(command NUL capability-list)
                       *PKT-LINE(command)
                       flush-pkt

  command           =  create / delete / update
  create            =  zero-id SP new-id  SP name
  delete            =  old-id  SP zero-id SP name
  update            =  old-id  SP new-id  SP name

  old-id            =  obj-id
  new-id            =  obj-id

  push-cert         = PKT-LINE("push-cert" NUL capability-list LF)
                      PKT-LINE("certificate version 0.1" LF)
                      PKT-LINE("pusher" SP ident LF)
                      PKT-LINE("pushee" SP url LF)
                      PKT-LINE("nonce" SP nonce LF)
                      *PKT-LINE("push-option" SP push-option LF)
                      PKT-LINE(LF)
                      *PKT-LINE(command LF)
                      *PKT-LINE(gpg-signature-lines LF)
                      PKT-LINE("push-cert-end" LF)

  push-option       =  1*( VCHAR | SP )

Если сервер объявил возможность push-options, а клиент указал push-options в приведённом выше списке возможностей, затем клиент отправляет параметры отправки, после которых передаётся flush-pkt.

  push-options      =  *PKT-LINE(push-option) flush-pkt

Для обеспечения обратной совместимости со старыми серверами Git, если клиент отправляет сертификат отправки и параметры отправки, он ДОЛЖЕН передать параметры отправки как внутри сертификата отправки, так и после него. (Обратите внимание: параметры отправки внутри сертификата имеют префикс, а параметры после сертификата — нет.) Эти два списка ДОЛЖНЫ совпадать, если не учитывать префикс.

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

  packfile          =  "PACK" 28*(OCTET)

Если принимающая сторона не поддерживает delete-refs, отправляющая сторона НЕ ДОЛЖНА запрашивать команду удаления.

Если принимающая сторона не поддерживает push-cert, отправляющая сторона НЕ ДОЛЖНА отправлять команду push-cert. При отправке команды push-cert команда command-list НЕ ДОЛЖНА передаваться; вместо неё используются команды, записанные в сертификате отправки.

Файл пакета НЕ ДОЛЖЕН отправляться, если используется только команда delete.

Файл пакета ДОЛЖЕН отправляться, если используется команда создания или обновления, даже если на сервере уже есть все необходимые объекты. В этом случае клиент ДОЛЖЕН отправить пустой файл пакета. Такое, скорее всего, произойдёт только при создании клиентом новой ветки или тега, указывающего на существующий obj-id.

Сервер получает файл пакета и распаковывает его, затем проверяет каждую обновляемую ссылку, убеждаясь, что она не изменилась во время обработки запроса (obj-id по-прежнему совпадает со старым значением), и запускает все хуки обновления, чтобы проверить допустимость обновления. Если всё в порядке, сервер обновляет ссылки.

Сертификат отправки

Сертификат отправки начинается с набора строк заголовка. После заголовка и пустой строки следуют команды протокола, по одной в строке. Обратите внимание, что завершающий LF в PKT-LINE сертификата отправки необязателен not; он должен присутствовать.

В настоящее время определены следующие поля заголовка:

pusher ident

Идентифицирует ключ GPG в формате «Человекочитаемое имя <email@address>».

pushee url

URL репозитория (анонимизированный, если URL содержит данные аутентификации), в который пользователь, выполнивший git push, намеревался отправить данные.

nonce nonce

Строка nonce, которую принимающий репозиторий попросил отправляющего пользователя включить в сертификат для предотвращения атак повторного воспроизведения.

Строки подписи GPG представляют собой отсоединённую подпись содержимого, записанного в сертификате отправки до начала блока подписи. Отсоединённая подпись подтверждает, что команды были заданы отправителем, который должен быть подписавшим.

Отчёт о состоянии

Получив данные пакета от отправителя, получатель отправляет отчёт, если включена возможность report-status или report-status-v2. Это краткий перечень результатов обновления. Сначала указывается состояние распаковки файла пакета: unpack ok или unpack [error]. Затем указывается состояние каждой ссылки, которую пытались обновить. Для каждой строки указывается ok [refname], если обновление прошло успешно, или ng [refname] [error], если оно завершилось неудачно.

  report-status     = unpack-status
                      1*(command-status)
                      flush-pkt

  unpack-status     = PKT-LINE("unpack" SP unpack-result)
  unpack-result     = "ok" / error-msg

  command-status    = command-ok / command-fail
  command-ok        = PKT-LINE("ok" SP refname)
  command-fail      = PKT-LINE("ng" SP refname SP error-msg)

  error-msg         = 1*(OCTET) ; where not "ok"

Возможность report-status-v2 расширяет протокол, добавляя новые строки параметров для поддержки отчётов о ссылках, переписанных хуком proc-receive. Хук proc-receive может обрабатывать команду для псевдоссылки, которая создаёт или обновляет одну или несколько ссылок; у каждой ссылки могут быть разные имя, новый oid и старый oid.

  report-status-v2  = unpack-status
                      1*(command-status-v2)
                      flush-pkt

  unpack-status     = PKT-LINE("unpack" SP unpack-result)
  unpack-result     = "ok" / error-msg

  command-status-v2 = command-ok-v2 / command-fail
  command-ok-v2     = command-ok
                      *option-line

  command-ok        = PKT-LINE("ok" SP refname)
  command-fail      = PKT-LINE("ng" SP refname SP error-msg)

  error-msg         = 1*(OCTET) ; where not "ok"

  option-line       = *1(option-refname)
                      *1(option-old-oid)
                      *1(option-new-oid)
                      *1(option-forced-update)

  option-refname    = PKT-LINE("option" SP "refname" SP refname)
  option-old-oid    = PKT-LINE("option" SP "old-oid" SP obj-id)
  option-new-oid    = PKT-LINE("option" SP "new-oid" SP obj-id)
  option-force      = PKT-LINE("option" SP "forced-update")

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

Пример обмена сообщениями между клиентом и сервером может выглядеть так:

   S: 006274730d410fcb6603ace96f1dc55ea6196122532d refs/heads/local\0report-status delete-refs ofs-delta\n
   S: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe refs/heads/debug\n
   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/master\n
   S: 003d74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/team\n
   S: 0000

   C: 00677d1665144a3a975c05f1f43902ddaf084e784dbe 74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/debug\n
   C: 006874730d410fcb6603ace96f1dc55ea6196122532d 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a refs/heads/master\n
   C: 0000
   C: [PACKDATA]

   S: 000eunpack ok\n
   S: 0018ok refs/heads/debug\n
   S: 002ang refs/heads/master non-fast-forward\n

gitprotocol-pack

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

Spec-Zone.ru

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