
# Protocollen

Pitmaster ondersteunt meerdere netwerktransportprotocollen voor communicatie met git-servers. Smart HTTP is het primaire transportprotocol. Er zijn aanvullende protocollen beschikbaar voor bredere compatibiliteit.

## Smart HTTP (primair)

Het aanbevolen transport. Werkt via HTTPS en is het meest gebruikte protocol. Er is geen API voor aangepaste headers of inloggegevens; inloggegevens kunnen alleen worden doorgegeven in de URL (`https://user:token@host/repo.git`), die PHP verstuurt als Basic-authenticatie. `clone()` slaat de URL, inclusief inloggegevens, op als `remote.origin.url` in `.git/config`. Verzoeken gebruiken de stream wrappers van PHP, dus `allow_url_fopen` moet zijn ingeschakeld.

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Zie [Smart HTTP](https://pitmaster.inline0.dev/nl/docs/network/smart-http) voor alle details.

### Protocol v1

Het traditionele smart HTTP-protocol. Alle refs worden tijdens de discovery verstuurd en de onderhandeling gebruikt want/have/done-regels.

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

### Protocol v2

Het nieuwere protocol met gestructureerde opdrachten (`ls-refs`, `fetch`). Efficiënter voor repositories met veel refs, omdat de client de lijst met refs kan filteren.

`clone()` en `fetch()` gebruiken altijd protocol v1. Protocol v2 is expliciet beschikbaar via smart HTTP met `SmartHttpClient::discoverRefsV2()` en `UploadPackClient::fetchV2()`.

## Dumb HTTP

Terugvaloptie voor servers die het smart HTTP-protocol niet ondersteunen. Het dumb-protocol haalt objecten en packs afzonderlijk op via gewone HTTP GET-verzoeken.

```php
use Pitmaster\Protocol\DumbHttpClient;

$client = new DumbHttpClient();
```

Beperkingen van Dumb HTTP:
- Geen onderhandeling (de client moet alles downloaden)
- Geen deltacompressie tijdens de overdracht
- Aanzienlijk trager dan smart HTTP
- Sommige servers (GitHub, GitLab) ondersteunen het niet

Het dumb-protocol haalt het volgende op:
1. `GET /info/refs` (platte tekst, geen pkt-line)
2. `GET /HEAD` (standaardbranch)
3. `GET /objects/info/packs` (lijst met beschikbare packs)
4. `GET /objects/pack/pack-<hash>.pack` en `.idx` (elke vermelde pack en de bijbehorende index)
5. `GET /objects/<xx>/<rest>` (afzonderlijke losse objecten, doorlopen vanaf de ref-tips)

Stap 5 wordt alleen uitgevoerd wanneer de server geen packs vermeldt. Wanneer de server wel packs vermeldt, worden objecten die alleen als losse bestanden op de server bestaan niet gedownload ([#18](https://github.com/inline0/pitmaster/issues/18)). De dumb-client accepteert alleen object-ID's van 40 tekens (SHA-1). `clone()` en `fetch()` vallen terug op dumb HTTP wanneer de smart HTTP-uitwisseling mislukt.

## SSH

Het transport SSH gebruikt de extensie `ssh2` PHP wanneer die is geladen. Anders start het de systeemclient `ssh` via `proc_open()`. In beide gevallen voert het `git-upload-pack` of `git-receive-pack` uit op de remote.

```php
use Pitmaster\Protocol\SshClient;

$client = new SshClient();
```

SSH-URL's:
```
git@github.com:user/repo.git
ssh://git@github.com/user/repo.git
```

Er is geen extensie vereist. De twee routes werken verschillend:

**Systeemclient `ssh`** (gebruikt wanneer `ssh2` niet is geladen). Pitmaster voert `ssh -o BatchMode=yes -o ConnectTimeout=30 -p <port> <user>@<host> <command>` uit, dus authenticatie en controle van host keys volgen uw configuratie van SSH en agent. Met deze omgevingsvariabelen past u de opdracht aan:

| Variabele | Effect |
|----------|--------|
| `PITMASTER_SSH_COMMAND` | Uitvoerbaar bestand dat wordt uitgevoerd in plaats van `ssh` |
| `PITMASTER_SSH_IDENTITY_FILE` | Doorgegeven als `-i <file>` |
| `PITMASTER_SSH_KNOWN_HOSTS` | Doorgegeven als `-o UserKnownHostsFile=<file>` |
| `PITMASTER_SSH_STRICT_HOST_KEY_CHECKING` | Doorgegeven als `-o StrictHostKeyChecking=<value>` |

Deze route start een proces en is daarom niet beschikbaar voor handles die zijn geopend met `['processes' => false]`.

**Extensie `ssh2`** (altijd de voorkeur wanneer geladen). Pitmaster authenticeert met `~/.ssh/id_rsa`, daarna met `~/.ssh/id_ed25519` als de RSA-sleutel aanwezig maar geweigerd is, en anders met de agent SSH. De variabelen `PITMASTER_SSH_*` worden genegeerd en de host key van de server wordt langs deze route niet geverifieerd ([#22](https://github.com/inline0/pitmaster/issues/22)).

Het transport SSH voert `git-upload-pack` of `git-receive-pack` als remote opdracht uit en communiceert via het kanaal SSH, met hetzelfde pkt-line-protocol als smart HTTP.

## Protocol Git (TCP)

Het native git-protocol communiceert via TCP-poort 9418 met PHP-sockets. `GitProtocolClient` implementeert het ontdekken van refs en `upload-pack` (ophalen); pushen is niet mogelijk. `clone()` en `fetch()` sturen `git://`-URL's er niet naartoe door, dus gebruik de client rechtstreeks.

```php
use Pitmaster\Protocol\GitProtocolClient;

$client = new GitProtocolClient();
```

Git-URL's:
```
git://github.com/user/repo.git
```

Kenmerken:
- Geen authenticatie (in de praktijk alleen-lezen)
- Geen versleuteling
- Door de meeste hostingproviders verouderd verklaard
- Gebruikt dezelfde pkt-line-framing als smart HTTP

Het git-protocol verstuurt de servicenaam en het repositorypad als eerste verzoek en gaat daarna verder met standaard pkt-line-refdetectie en pack-onderhandeling.

## Bundels

Git-bundels zijn offline pack-bestanden met ref-informatie. Hiermee kunt u repositorygegevens overdragen zonder netwerkverbinding.

```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 leest de bundelheaders v2 en v3. Er is geen `Repository`-methode om een bundel te importeren: schrijf `packData()` naar `.git/objects/pack/`, bouw de index met `PackIndexer::writeIndex()` en werk de refs zelf bij.

Bundelformaat:
```
# v2 git bundle\n
-<prerequisite hash>\n    (zero or more)
<hash> <refname>\n        (one or more)
\n
<pack data>               (standard pack file format)
```

Bundels zijn handig voor:
- Overdrachten via USB-sticks
- Incrementele back-ups
- Clones klaarzetten in omgevingen zonder netwerkverbinding

## Shallow clones

Pitmaster ondersteunt shallow clones, waarbij slechts een beperkte diepte van de commitgeschiedenis wordt opgehaald.

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

Geef een diepte door aan `Pitmaster::clone($url, $path, $depth)` of `$repo->fetch($remote, $depth)`. Het verzoek voegt de capability `shallow` en een `deepen`-regel toe:
```
want <hash>
deepen <depth>
```

De server reageert met `shallow <hash>`-regels die aangeven waar de geschiedenis is afgekapt. Pitmaster berekent de shallow-grens op basis van de diepte zelf en gebruikt de `shallow`-regels van de server wanneer die berekening niets oplevert; het resultaat wordt opgeslagen in `.git/shallow`. `ShallowClone::readShallow()`, `writeShallow()` en `isShallow()` werken rechtstreeks met dat bestand.

## Protocolvergelijking

| Protocol | Authenticatie | Versleuteling | Push | Typisch gebruik |
|----------|---------------|--------------|------|-----------------|
| Smart HTTP | Inloggegevens in de URL | HTTPS | Ja | Primair transport |
| Dumb HTTP | Inloggegevens in de URL | HTTPS | Nee | Terugvaloptie voor oudere systemen |
| SSH | Sleutels SSH of agent | SSH | Ja | Privérepositories, CI |
| Git (TCP) | Geen | Geen | Nee | Mirrors met alleen-leestoegang |
| Bundel | N.v.t. | N.v.t. | N.v.t. | Offlineoverdracht |

## Transport selecteren

`Pitmaster::clone()`, `$repo->fetch()` en `$repo->push()` selecteren het transport op basis van de URL:

| Patroon van URL | Transport |
|------------|-----------|
| `ssh://...` | SSH |
| `user@host:path` | SSH |
| Al het andere (`https://...`, `http://...`) | Smart HTTP; clone en fetch vallen terug op dumb HTTP |

`git://`-URL's en lokale paden worden niet ondersteund door deze methoden: ze worden naar de smart HTTP-client gestuurd en mislukken. Gebruik `GitProtocolClient` rechtstreeks voor `git://`. Een HTTPS URL met zowel een gebruiker als een poort (`https://user@host:8443/repo.git`) wordt momenteel ten onrechte herkend als een SSH URL ([#17](https://github.com/inline0/pitmaster/issues/17)).
