
# Protokolle

Pitmaster unterstützt mehrere Netzwerktransportprotokolle für die Kommunikation mit git-Servern. Smart-HTTP ist der primäre Transport. Weitere Protokolle sorgen für umfassendere Kompatibilität.

## Smart HTTP (primär)

Der empfohlene Transport. Funktioniert über HTTPS und ist das am weitesten verbreitete Protokoll. Es gibt kein API für benutzerdefinierte Header oder Zugangsdaten. Zugangsdaten lassen sich nur in URL (`https://user:token@host/repo.git`) übergeben, die PHP als Basic-Authentifizierung sendet. `clone()` speichert das URL einschließlich der Zugangsdaten als `remote.origin.url` in `.git/config`. Anfragen verwenden die Stream-Wrapper von PHP, daher muss `allow_url_fopen` aktiviert sein.

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Ausführliche Informationen findest du unter [Smart HTTP](https://pitmaster.inline0.dev/de/docs/network/smart-http).

### Protokoll v1

Das traditionelle Smart-HTTP-Protokoll. Bei der Ermittlung werden alle Refs gesendet; die Aushandlung nutzt Want-, Have- und Done-Zeilen.

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

### Protokoll v2

Das neuere Protokoll mit strukturierten Befehlen (`ls-refs`, `fetch`). Effizienter bei Repositories mit vielen Refs, da der Client die Ref-Liste filtern kann.

`clone()` und `fetch()` verwenden immer Protokoll v1. Protokoll v2 ist explizit über Smart HTTP mit `SmartHttpClient::discoverRefsV2()` und `UploadPackClient::fetchV2()` verfügbar.

## Dumb HTTP

Fallback für Server, die das Smart-HTTP-Protokoll nicht unterstützen. Das Dumb-Protokoll ruft Objekte und Packs einzeln über einfache HTTP-GET-Anfragen ab.

```php
use Pitmaster\Protocol\DumbHttpClient;

$client = new DumbHttpClient();
```

Einschränkungen von Dumb HTTP:
- Keine Aushandlung (der Client muss alles herunterladen)
- Keine Delta-Komprimierung während der Übertragung
- Deutlich langsamer als Smart HTTP
- Einige Server (GitHub, GitLab) unterstützen es nicht

Das Dumb-Protokoll ruft Folgendes ab:
1. `GET /info/refs` (Klartext, kein pkt-line)
2. `GET /HEAD` (Standard-Branch)
3. `GET /objects/info/packs` (Liste verfügbarer Packs)
4. `GET /objects/pack/pack-<hash>.pack` und `.idx` (jedes aufgeführte Pack und sein Index)
5. `GET /objects/<xx>/<rest>` (einzelne lose Objekte, ausgehend von den Ref-Tips durchsucht)

Schritt 5 wird nur ausgeführt, wenn der Server keine Packs aufführt. Listet er Packs auf, werden Objekte, die auf dem Server nur als lose Dateien vorliegen, nicht heruntergeladen ([#18](https://github.com/inline0/pitmaster/issues/18)). Der Dumb-Client akzeptiert nur 40-stellige Objekt-IDs (SHA-1). `clone()` und `fetch()` greifen auf Dumb HTTP zurück, wenn der Smart-HTTP-Austausch fehlschlägt.

## SSH

Der SSH-Transport verwendet die Erweiterung `ssh2` PHP, wenn sie geladen ist. Andernfalls startet er den System-`ssh`-Client über `proc_open()`. In beiden Fällen wird auf dem Remote `git-upload-pack` oder `git-receive-pack` ausgeführt.

```php
use Pitmaster\Protocol\SshClient;

$client = new SshClient();
```

SSH-URLs:
```
git@github.com:user/repo.git
ssh://git@github.com/user/repo.git
```

Eine Erweiterung ist nicht erforderlich. Die beiden Wege verhalten sich unterschiedlich:

**System-`ssh`-Client** (wird verwendet, wenn `ssh2` nicht geladen ist). Pitmaster führt `ssh -o BatchMode=yes -o ConnectTimeout=30 -p <port> <user>@<host> <command>` aus. Authentifizierung und Host-Key-Prüfung richten sich daher nach deiner SSH-Konfiguration und deinem Agent. Mit diesen Umgebungsvariablen lässt sich der Befehl anpassen:

| Variable | Wirkung |
|----------|--------|
| `PITMASTER_SSH_COMMAND` | Auszuführbare Datei anstelle von `ssh` |
| `PITMASTER_SSH_IDENTITY_FILE` | Wird als `-i <file>` übergeben |
| `PITMASTER_SSH_KNOWN_HOSTS` | Wird als `-o UserKnownHostsFile=<file>` übergeben |
| `PITMASTER_SSH_STRICT_HOST_KEY_CHECKING` | Wird als `-o StrictHostKeyChecking=<value>` übergeben |

Dieser Weg startet einen Prozess und ist daher bei Handles, die mit `['processes' => false]` geöffnet wurden, nicht verfügbar.

**`ssh2`-Erweiterung** (wird bei Verfügbarkeit immer bevorzugt). Pitmaster authentifiziert sich mit `~/.ssh/id_rsa`, dann mit `~/.ssh/id_ed25519`, falls der RSA-Schlüssel vorhanden, aber abgelehnt wird, und andernfalls über den SSH-Agent. Die Variablen `PITMASTER_SSH_*` werden ignoriert und der Host-Key des Servers wird bei diesem Weg nicht geprüft ([#22](https://github.com/inline0/pitmaster/issues/22)).

Der SSH-Transport führt `git-upload-pack` oder `git-receive-pack` als Remote-Befehl aus und kommuniziert über den SSH-Kanal mit demselben pkt-line-Protokoll wie Smart HTTP.

## Git-Protokoll (TCP)

Das native git-Protokoll kommuniziert über TCP-Port 9418 mit PHP-Sockets. `GitProtocolClient` implementiert die Ref-Erkennung und `upload-pack` (Abruf), kann aber keine Daten übertragen. `clone()` und `fetch()` leiten `git://`-URLs nicht dorthin weiter; verwende daher direkt den Client.

```php
use Pitmaster\Protocol\GitProtocolClient;

$client = new GitProtocolClient();
```

Git-URLs:
```
git://github.com/user/repo.git
```

Eigenschaften:
- Keine Authentifizierung (in der Praxis schreibgeschützt)
- Keine Verschlüsselung
- Von den meisten Hosting-Anbietern als veraltet eingestuft
- Verwendet dasselbe pkt-line-Framing wie Smart HTTP

Das Protokoll git sendet den Dienstnamen und den Repository-Pfad als erste Anfrage. Danach folgt die standardmäßige Ref-Erkennung und Pack-Aushandlung im pkt-line-Format.

## Bundles

Git-Bundles sind Offline-Packdateien mit Ref-Informationen. Sie ermöglichen die Übertragung von Repository-Daten ohne Netzwerkverbindung.

```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 liest Bundle-Header der Versionen v2 und v3. Eine `Repository`-Methode zum Importieren eines Bundles gibt es nicht: Schreibe `packData()` nach `.git/objects/pack/`, erstelle den Index mit `PackIndexer::writeIndex()` und aktualisiere die Refs selbst.

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

Bundles eignen sich für:
- Übertragungen per USB-Laufwerk
- Inkrementelle Backups
- Das Bereitstellen von Klonen in abgeschotteten Umgebungen

## Shallow-Klone

Pitmaster unterstützt Shallow-Klone, bei denen nur eine begrenzte Tiefe des Commit-Verlaufs abgerufen wird.

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

Übergib `Pitmaster::clone($url, $path, $depth)` oder `$repo->fetch($remote, $depth)` eine Tiefe. Die Anfrage fügt die Fähigkeit `shallow` und eine `deepen`-Zeile hinzu:
```
want <hash>
deepen <depth>
```

Der Server antwortet mit `shallow <hash>`-Zeilen, die angeben, wo der Verlauf abgeschnitten wurde. Pitmaster berechnet die flache Grenze anhand der Tiefe selbst und verwendet die `shallow`-Zeilen des Servers, wenn diese Berechnung nichts ergibt. Das Ergebnis wird in `.git/shallow` gespeichert. `ShallowClone::readShallow()`, `writeShallow()` und `isShallow()` arbeiten direkt mit dieser Datei.

## Protokollvergleich

| Protokoll | Authentifizierung | Verschlüsselung | Übertragung | Typische Verwendung |
|----------|------|-----------|------|-------------|
| Smart HTTP | Zugangsdaten in URL | HTTPS | Ja | Primärer Transport |
| Dumb HTTP | Zugangsdaten in URL | HTTPS | Nein | Legacy-Fallback |
| SSH | SSH-Schlüssel oder Agent | SSH | Ja | Private Repositories, CI |
| Git (TCP) | Keine | Keine | Nein | Spiegel mit Lesezugriff |
| Bundle | Nicht zutreffend | Nicht zutreffend | Nicht zutreffend | Offline-Übertragung |

## Transportauswahl

`Pitmaster::clone()`, `$repo->fetch()` und `$repo->push()` wählen den Transport anhand von URL aus:

| Muster von URL | Transport |
|------------|-----------|
| `ssh://...` | SSH |
| `user@host:path` | SSH |
| Alles andere (`https://...`, `http://...`) | Smart HTTP; Klonen und Abrufen greifen auf Dumb HTTP zurück |

`git://`-URLs und lokale Pfade werden von diesen Methoden nicht unterstützt: Sie werden an den Smart-HTTP-Client weitergegeben und schlagen fehl. Verwende für `git://` direkt `GitProtocolClient`. Ein HTTPS URL, das sowohl einen Benutzer als auch einen Port enthält (`https://user@host:8443/repo.git`), wird derzeit fälschlich als SSH-URL erkannt ([#17](https://github.com/inline0/pitmaster/issues/17)).
