
# Protokoly

Pitmaster podporuje několik síťových transportních protokolů pro komunikaci se servery git. Hlavním transportním protokolem je Smart HTTP. Pro širší kompatibilitu jsou k dispozici i další protokoly.

## Smart HTTP (hlavní)

Doporučený transport. Funguje přes HTTPS a jde o nejrozšířenější protokol. Pro vlastní hlavičky nebo přihlašovací údaje není k dispozici API; přihlašovací údaje lze předat pouze v URL (`https://user:token@host/repo.git`), které PHP odesílá jako základní ověření. `clone()` ukládá URL, včetně přihlašovacích údajů, jako `remote.origin.url` v `.git/config`. Požadavky používají proudové obaly PHP, proto musí být povoleno `allow_url_fopen`.

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Podrobnosti najdete v části [Smart HTTP](https://pitmaster.inline0.dev/cs/docs/network/smart-http).

### Protokol v1

Tradiční protokol smart HTTP. Při zjišťování se odešlou všechny reference a vyjednávání používá řádky want/have/done.

```php
use Pitmaster\Protocol\ProtocolV1;
```

### Protokol v2

Novější protokol se strukturovanými příkazy (`ls-refs`, `fetch`). Je efektivnější pro repozitáře s mnoha referencemi, protože klient může seznam referencí filtrovat.

`clone()` a `fetch()` vždy používají protokol v1. Protokol v2 je dostupný výslovně přes smart HTTP prostřednictvím `SmartHttpClient::discoverRefsV2()` a `UploadPackClient::fetchV2()`.

## Hloupý HTTP

Záložní řešení pro servery, které nepodporují protokol smart HTTP. Hloupý protokol stahuje objekty a packy jednotlivě pomocí běžných požadavků HTTP GET.

```php
use Pitmaster\Protocol\DumbHttpClient;

$client = new DumbHttpClient();
```

Omezení hloupého HTTP:
- Bez vyjednávání (klient musí stáhnout vše)
- Během přenosu se nepoužívá delta komprese
- Výrazně pomalejší než smart HTTP
- Některé servery (GitHub, GitLab) ho nepodporují

Hloupý protokol stahuje:
1. `GET /info/refs` (prostý text, bez pkt-line)
2. `GET /HEAD` (výchozí větev)
3. `GET /objects/info/packs` (seznam dostupných packů)
4. `GET /objects/pack/pack-<hash>.pack` a `.idx` (každý uvedený pack a jeho index)
5. `GET /objects/<xx>/<rest>` (jednotlivé volné objekty procházené od špiček referencí)

Krok 5 se provede pouze tehdy, když server neuvede žádné packy. Pokud packy uvede, objekty, které na serveru existují pouze jako volné soubory, se nestáhnou ([#18](https://github.com/inline0/pitmaster/issues/18)). Hloupý klient přijímá pouze ID objektů o délce 40 znaků (SHA-1). `clone()` a `fetch()` přejdou na hloupý HTTP, pokud výměna přes smart HTTP selže.

## SSH

Transport SSH používá rozšíření `ssh2` PHP, pokud je načtené. Jinak spustí systémového klienta `ssh` prostřednictvím `proc_open()`. V obou případech na vzdáleném serveru spustí `git-upload-pack` nebo `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
```

Není potřeba žádné rozšíření. Obě cesty se chovají odlišně:

**Systémový klient `ssh`** (používá se, když není načteno `ssh2`). Pitmaster spouští `ssh -o BatchMode=yes -o ConnectTimeout=30 -p <port> <user>@<host> <command>`, takže ověřování a kontrola hostitelského klíče se řídí konfigurací a agentem SSH. Tyto proměnné prostředí upravují příkaz:

| Proměnná | Účinek |
|----------|--------|
| `PITMASTER_SSH_COMMAND` | Spustitelný soubor, který se spustí místo `ssh` |
| `PITMASTER_SSH_IDENTITY_FILE` | Předává se jako `-i <file>` |
| `PITMASTER_SSH_KNOWN_HOSTS` | Předává se jako `-o UserKnownHostsFile=<file>` |
| `PITMASTER_SSH_STRICT_HOST_KEY_CHECKING` | Předává se jako `-o StrictHostKeyChecking=<value>` |

Tato cesta spouští proces, takže není dostupná pro handly otevřené pomocí `['processes' => false]`.

**Rozšíření `ssh2`** (po načtení má vždy přednost). Pitmaster se ověří pomocí `~/.ssh/id_rsa`, poté pomocí `~/.ssh/id_ed25519`, pokud je klíč RSA přítomen, ale odmítnut, a jinak pomocí agenta SSH. Proměnné `PITMASTER_SSH_*` se ignorují a hostitelský klíč serveru se touto cestou neověřuje ([#22](https://github.com/inline0/pitmaster/issues/22)).

Transport SSH spouští `git-upload-pack` nebo `git-receive-pack` jako vzdálený příkaz a komunikuje přes kanál SSH za použití stejného protokolu pkt-line jako smart HTTP.

## Protokol Git (TCP)

Nativní protokol git komunikuje přes port TCP 9418 pomocí soketů PHP. `GitProtocolClient` zajišťuje zjišťování odkazů a `upload-pack` (načítání); odesílat neumí. `clone()` ani `fetch()` k němu nesměrují adresy URL `git://`, proto použijte klienta přímo.

```php
use Pitmaster\Protocol\GitProtocolClient;

$client = new GitProtocolClient();
```

URL Git:
```
git://github.com/user/repo.git
```

Vlastnosti:
- Bez ověřování (v praxi pouze pro čtení)
- Bez šifrování
- Většina poskytovatelů hostingu jej označila za zastaralý
- Používá stejné rámování pkt-line jako smart HTTP

Protokol git odešle název služby a cestu k repozitáři jako úvodní požadavek a poté pokračuje standardním zjišťováním odkazů a vyjednáváním o balíčku pomocí pkt-line.

## Balíčky

Balíčky Git jsou offline soubory packů s informacemi o referencích. Umožňují přenášet data repozitáře bez síťového připojení.

```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 čte hlavičky balíčků v2 a v3. Neexistuje žádná metoda `Repository` pro import balíčku: zapište `packData()` do `.git/objects/pack/`, vytvořte jeho index pomocí `PackIndexer::writeIndex()` a reference aktualizujte sami.

Formát balíčku:
```
# v2 git bundle\n
-<prerequisite hash>\n    (zero or more)
<hash> <refname>\n        (one or more)
\n
<pack data>               (standard pack file format)
```

Balíčky se hodí pro:
- Přenosy pomocí „sneakernetu“ (USB disky)
- Přírůstkové zálohy
- Předání klonů do prostředí bez síťového připojení

## Mělké klony

Pitmaster podporuje mělké klony, které stahují pouze omezenou hloubku historie commitů.

```php
use Pitmaster\Protocol\ShallowClone;
```

Předejte hloubku do `Pitmaster::clone($url, $path, $depth)` nebo `$repo->fetch($remote, $depth)`. Požadavek přidá schopnost `shallow` a řádek `deepen`:
```
want <hash>
deepen <depth>
```

Server odpovídá řádky `shallow <hash>`, které označují místo zkrácení historie. Pitmaster vypočítá hranici mělké historie ze samotné hloubky a použije řádky `shallow` ze serveru, pokud výpočet nic nenajde; výsledek se uloží do `.git/shallow`. `ShallowClone::readShallow()`, `writeShallow()` a `isShallow()` pracují přímo s tímto souborem.

## Porovnání protokolů

| Protokol | Ověření | Šifrování | Push | Typické použití |
|----------|------|-----------|------|-------------|
| Smart HTTP | Přihlašovací údaje v URL | HTTPS | Ano | Hlavní transport |
| Hloupý HTTP | Přihlašovací údaje v URL | HTTPS | Ne | Záložní řešení pro starší systémy |
| SSH | Klíče SSH nebo agent | SSH | Ano | Soukromé repozitáře, CI |
| Git (TCP) | Žádné | Žádné | Ne | Zrcadla pouze pro čtení |
| Balíček | N/A | N/A | N/A | Offline přenos |

## Výběr transportu

`Pitmaster::clone()`, `$repo->fetch()` a `$repo->push()` vybírají transport podle URL:

| Vzor URL | Transport |
|------------|-----------|
| `ssh://...` | SSH |
| `user@host:path` | SSH |
| Cokoli jiného (`https://...`, `http://...`) | Smart HTTP; clone a fetch přejdou na hloupý HTTP |

Metody nepodporují URL `git://` ani místní cesty: předají se klientovi smart HTTP a selžou. Pro `git://` použijte přímo `GitProtocolClient`. HTTPS URL obsahující uživatele i port (`https://user@host:8443/repo.git`) je v současnosti chybně považováno za SSH URL ([#17](https://github.com/inline0/pitmaster/issues/17)).
