Перейти к содержимому

Протоколы

Pitmaster поддерживает несколько транспортных сетевых протоколов для связи с серверами git. Основной транспорт — Smart HTTP. Для большей совместимости доступны и другие протоколы.

Smart HTTP (основной)

Рекомендуемый транспорт. Работает поверх HTTPS и является наиболее распространённым протоколом. Для пользовательских заголовков или учётных данных нет API; учётные данные можно передать только в URL (https://user:token@host/repo.git), который PHP отправляет для базовой аутентификации. clone() сохраняет URL, включая учётные данные, в remote.origin.url в .git/config. Запросы используют потоковые обёртки PHP, поэтому необходимо включить allow_url_fopen.

PHP
use Pitmaster\Protocol\SmartHttpClient;

$http = new SmartHttpClient(timeout: 30);
$discovery = $http->discoverRefs('https://github.com/user/repo.git');

Подробнее см. в разделе Smart HTTP.

Протокол v1

Традиционный протокол smart HTTP. При обнаружении отправляются все ссылки, а согласование выполняется с помощью строк want/have/done.

PHP
use Pitmaster\Protocol\ProtocolV1;

Протокол v2

Более новый протокол со структурированными командами (ls-refs, fetch). Эффективнее для репозиториев с большим количеством ссылок: клиент может отфильтровать их список.

clone() и fetch() всегда используют протокол v1. Протокол v2 можно явно использовать через smart HTTP с помощью SmartHttpClient::discoverRefsV2() и UploadPackClient::fetchV2().

Простой HTTP

Резервный вариант для серверов, не поддерживающих протокол smart HTTP. Протокол dumb по отдельности загружает объекты и pack-файлы с помощью обычных GET-запросов HTTP.

PHP
use Pitmaster\Protocol\DumbHttpClient;

$client = new DumbHttpClient();

Ограничения Dumb HTTP:

  • Нет согласования (клиент должен скачать всё)
  • Нет дельта-сжатия при передаче
  • Значительно медленнее, чем smart HTTP
  • Некоторые серверы (GitHub, GitLab) его не поддерживают

Протокол dumb загружает:

  1. GET /info/refs (обычный текст, без pkt-line)
  2. GET /HEAD (ветку по умолчанию)
  3. GET /objects/info/packs (список доступных pack-файлов)
  4. GET /objects/pack/pack-<hash>.pack и .idx (каждый указанный pack-файл и его индекс)
  5. GET /objects/<xx>/<rest> (отдельные свободные объекты, обход начиная с вершин ссылок)

Шаг 5 выполняется только тогда, когда сервер не указывает pack-файлы. Если pack-файлы указаны, объекты, существующие на сервере только в виде отдельных файлов, не загружаются (#18). Клиент dumb принимает только идентификаторы объектов длиной 40 символов (SHA-1). Если обмен smart HTTP завершается с ошибкой, clone() и fetch() используют резервный вариант dumb HTTP.

SSH

Транспорт SSH использует расширение ssh2 PHP, если оно загружено. Иначе он запускает системный клиент ssh через proc_open(). В обоих случаях на удалённом сервере выполняется git-upload-pack или git-receive-pack.

PHP
use Pitmaster\Protocol\SshClient;

$client = new SshClient();

URL SSH:

Код
git@github.com:user/repo.git
ssh://git@github.com/user/repo.git

Расширение не требуется. Эти два способа работают по-разному:

Системный клиент ssh (используется, если ssh2 не загружен). Pitmaster запускает ssh -o BatchMode=yes -o ConnectTimeout=30 -p <port> <user>@<host> <command>, поэтому аутентификация и проверка ключа хоста выполняются согласно конфигурации SSH и настройкам агента. Эти переменные окружения изменяют команду:

Переменная Действие
PITMASTER_SSH_COMMAND Исполняемый файл вместо ssh
PITMASTER_SSH_IDENTITY_FILE Передаётся как -i <file>
PITMASTER_SSH_KNOWN_HOSTS Передаётся как -o UserKnownHostsFile=<file>
PITMASTER_SSH_STRICT_HOST_KEY_CHECKING Передаётся как -o StrictHostKeyChecking=<value>

Этот способ запускает процесс, поэтому недоступен для дескрипторов, открытых с помощью ['processes' => false].

Расширение ssh2 (всегда имеет приоритет, если загружено). Pitmaster выполняет аутентификацию с помощью ~/.ssh/id_rsa, затем ~/.ssh/id_ed25519, если ключ RSA присутствует, но отклонён, и в остальных случаях — с помощью агента SSH. Переменные PITMASTER_SSH_* игнорируются, а ключ хоста сервера при этом способе не проверяется (#22).

Транспорт SSH запускает git-upload-pack или git-receive-pack как удалённую команду и обменивается данными по каналу SSH, используя тот же протокол pkt-line, что и smart HTTP.

Протокол Git (TCP)

Встроенный протокол git обменивается данными через TCP-порт 9418 с помощью сокетов PHP. GitProtocolClient реализует обнаружение ссылок и upload-pack (загрузку); отправлять данные он не может. clone() и fetch() не направляют URL git:// этому протоколу, поэтому используйте клиент напрямую.

PHP
use Pitmaster\Protocol\GitProtocolClient;

$client = new GitProtocolClient();

URL Git:

Код
git://github.com/user/repo.git

Характеристики:

  • Нет аутентификации (на практике доступ только для чтения)
  • Нет шифрования
  • Большинство хостинг-провайдеров признали протокол устаревшим
  • Используется такое же кадрирование pkt-line, как в smart HTTP

Протокол git отправляет имя службы и путь к репозиторию в начальном запросе, после чего выполняются стандартное обнаружение ссылок с pkt-line и согласование pack.

Bundle-файлы

Bundle-файлы Git — это автономные pack-файлы с информацией о ссылках. Они позволяют передавать данные репозитория без сетевого подключения.

PHP
use Pitmaster\Protocol\Bundle;

// Read a bundle file
$bundle = Bundle::open('/path/to/repo.bundle');
$refs = $bundle->refs();
$packData = $bundle->packData();
$prerequisites = $bundle->prerequisites();

// Create one
$bundle = Bundle::create(['refs/heads/main' => $commitId], $packData);
$bundle->writeTo('/path/to/out.bundle');

Pitmaster читает заголовки bundle-файлов v2 и v3. Отдельного метода Repository для импорта bundle-файла нет: запишите packData() в .git/objects/pack/, создайте индекс с помощью PackIndexer::writeIndex() и самостоятельно обновите ссылки.

Формат bundle-файла:

Код
# v2 git bundle\n
-<prerequisite hash>\n    (zero or more)
<hash> <refname>\n        (one or more)
\n
<pack data>               (standard pack file format)

Bundle-файлы полезны для:

  • Передачи данных без сети (USB-накопители)
  • Инкрементального резервного копирования
  • Создания начальных клонов в изолированных от сети средах

Неглубокие клоны

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

PHP
use Pitmaster\Protocol\ShallowClone;

Передайте глубину в Pitmaster::clone($url, $path, $depth) или $repo->fetch($remote, $depth). Запрос добавляет возможность shallow и строку deepen:

Код
want <hash>
deepen <depth>

Сервер отвечает строками shallow <hash>, обозначающими место усечения истории. Pitmaster вычисляет границу неглубокой истории по заданной глубине и использует строки shallow сервера, если вычислить её не удалось; результат сохраняется в .git/shallow. Файлом напрямую работают ShallowClone::readShallow(), writeShallow() и isShallow().

Сравнение протоколов

Протокол Аутентификация Шифрование Отправка Типичное применение
Smart HTTP Учётные данные в URL HTTPS Да Основной транспорт
Dumb HTTP Учётные данные в URL HTTPS Нет Резервный вариант для старых систем
SSH Ключи или агент SSH SSH Да Закрытые репозитории, CI
Git (TCP) Нет Нет Нет Зеркала только для чтения
Bundle Не применимо Не применимо Не применимо Передача без сети

Выбор транспорта

Pitmaster::clone(), $repo->fetch() и $repo->push() выбирают транспорт по URL:

Шаблон URL Транспорт
ssh://... SSH
user@host:path SSH
Всё остальное (https://..., http://...) Smart HTTP; для clone и fetch предусмотрен резервный вариант dumb HTTP

Методы не поддерживают URL git:// и локальные пути: они передаются клиенту smart HTTP, где завершаются с ошибкой. Для git:// используйте напрямую GitProtocolClient. HTTPS URL, содержащий имя пользователя и порт (https://user@host:8443/repo.git), сейчас ошибочно распознаётся как SSH URL (#17).