Протоколи
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 має бути ввімкнено.
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.
use Pitmaster\Protocol\ProtocolV1;
Протокол v2
Новіший протокол зі структурованими командами (ls-refs, fetch). Ефективніший для репозиторіїв із багатьма посиланнями, оскільки клієнт може фільтрувати їхній список.
clone() і fetch() завжди використовують протокол v1. Протокол v2 можна явно використати через smart HTTP за допомогою SmartHttpClient::discoverRefsV2() і UploadPackClient::fetchV2().
Розумний HTTP
Резервний варіант для серверів, які не підтримують протокол smart HTTP. Протокол dumb завантажує об’єкти й пакети окремо за допомогою звичайних запитів HTTP GET.
use Pitmaster\Protocol\DumbHttpClient;
$client = new DumbHttpClient();
Обмеження Dumb HTTP:
- Немає узгодження (клієнт має завантажити все)
- Під час передавання немає дельта-стиснення
- Значно повільніший за Smart HTTP
- Деякі сервери (GitHub, GitLab) його не підтримують
Протокол dumb завантажує:
GET /info/refs(звичайний текст, без pkt-line)GET /HEAD(гілка за замовчуванням)GET /objects/info/packs(список доступних пакетів)GET /objects/pack/pack-<hash>.packі.idx(кожен зазначений пакет та його індекс)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.
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:// до нього, тож використовуйте клієнт безпосередньо.
use Pitmaster\Protocol\GitProtocolClient;
$client = new GitProtocolClient();
URL-адреси Git:
git://github.com/user/repo.git
Характеристики:
- Без автентифікації (фактично лише для читання)
- Без шифрування
- Більшість хостинг-провайдерів вважають його застарілим
- Використовує те саме кадрування pkt-line, що й smart HTTP
Протокол git надсилає назву служби та шлях до репозиторію в першому запиті, а потім виконує стандартне виявлення посилань pkt-line та узгодження пакета.
Пакети Bundle
Пакети Git — це автономні файли пакетів із інформацією про посилання. Вони дають змогу передавати дані репозиторію без мережевого з’єднання.
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 підтримує поверхневі клони, у яких завантажується лише обмежена глибина історії комітів.
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).