Перейти до вмісту

Протоколи

Pitmaster підтримує кілька мережевих транспортних протоколів для зв’язку із серверами git. Основним транспортом є Smart HTTP. Для ширшої сумісності доступні додаткові протоколи.

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

Рекомендований транспорт. Працює через HTTPS і є найпоширенішим протоколом. Для власних заголовків або облікових даних API немає; облікові дані можна передати лише в URL (https://user:token@host/repo.git), які PHP надсилає як автентифікацію Basic. 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 завантажує об’єкти й пакети окремо за допомогою звичайних запитів HTTP GET.

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 (список доступних пакетів)
  4. GET /objects/pack/pack-<hash>.pack і .idx (кожен зазначений пакет та його індекс)
  5. GET /objects/<xx>/<rest> (окремі вільні об’єкти, обхід починається з вершин посилань)

Крок 5 виконується, лише якщо сервер не перелічує пакети. Якщо пакети перелічено, об’єкти, що є на сервері лише як вільні файли, не завантажуються (#18). Клієнт dumb приймає лише ідентифікатори об’єктів завдовжки 40 символів (SHA-1). clone() і fetch() переходять на dumb HTTP, якщо обмін даними через smart 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 та узгодження пакета.

Пакети Bundle

Пакети Git — це автономні файли пакетів із інформацією про посилання. Вони дають змогу передавати дані репозиторію без мережевого з’єднання.

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 читає заголовки пакетів v2 і v3. Способу Repository імпортувати пакет немає: запишіть packData() у .git/objects/pack/, створіть його індекс за допомогою PackIndexer::writeIndex() і оновіть посилання самостійно.

Формат пакета:

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

Пакети корисні для:

  • Передавання даних без мережі (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() працюють безпосередньо з цим файлом.

Порівняння протоколів

Протокол Автентифікація Шифрування Push Типове використання
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

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