
# Protocoles

Pitmaster prend en charge plusieurs protocoles de transport réseau pour communiquer avec les serveurs git. HTTP intelligent est le transport principal. D’autres protocoles sont disponibles pour une meilleure compatibilité.

## HTTP intelligent (principal)

Le transport recommandé. Il fonctionne sur HTTPS et constitue le protocole le plus largement déployé. Il n’existe pas de API pour les en-têtes personnalisés ou les identifiants ; ceux-ci ne peuvent être transmis que dans URL (`https://user:token@host/repo.git`), qu’PHP envoie en authentification Basic. `clone()` stocke le URL, identifiants compris, comme `remote.origin.url` dans `.git/config`. Les requêtes utilisent les wrappers de flux de PHP ; `allow_url_fopen` doit donc être activé.

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Voir [HTTP intelligent](https://pitmaster.inline0.dev/fr/docs/network/smart-http) pour tous les détails.

### Protocole v1

Le protocole intelligent HTTP traditionnel. Toutes les références sont envoyées lors de la découverte, et la négociation utilise les lignes want/have/done.

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

### Protocole v2

Le protocole plus récent, avec des commandes structurées (`ls-refs`, `fetch`). Il est plus efficace pour les dépôts ayant de nombreuses références, car le client peut filtrer la liste.

`clone()` et `fetch()` utilisent toujours le protocole v1. Le protocole v2 est disponible explicitement via `SmartHttpClient::discoverRefsV2()` et `UploadPackClient::fetchV2()` sur HTTP intelligent.

## HTTP simple

Solution de repli pour les serveurs qui ne prennent pas en charge le protocole HTTP intelligent. Le protocole simple récupère les objets et les packs individuellement au moyen de requêtes GET HTTP ordinaires.

```php
use Pitmaster\Protocol\DumbHttpClient;

$client = new DumbHttpClient();
```

Limites de HTTP simple :
- Aucune négociation (le client doit tout télécharger)
- Aucune compression delta pendant le transfert
- Beaucoup plus lent que HTTP intelligent
- Certains serveurs (GitHub, GitLab) ne le prennent pas en charge

Le protocole simple récupère :
1. `GET /info/refs` (texte brut, sans pkt-line)
2. `GET /HEAD` (branche par défaut)
3. `GET /objects/info/packs` (liste des packs disponibles)
4. `GET /objects/pack/pack-<hash>.pack` et `.idx` (chaque pack répertorié et son index)
5. `GET /objects/<xx>/<rest>` (objets libres individuels, parcourus depuis les pointes des références)

L’étape 5 n’est exécutée que si le serveur ne répertorie aucun pack. S’il en répertorie, les objets qui n’existent que sous forme de fichiers libres sur le serveur ne sont pas téléchargés ([#18](https://github.com/inline0/pitmaster/issues/18)). Le client simple n’accepte que les ID d’objet de 40 caractères (SHA-1). `clone()` et `fetch()` basculent sur HTTP simple lorsque l’échange HTTP intelligent échoue.

## SSH

Le transport SSH utilise l’extension `ssh2` PHP lorsqu’elle est chargée. Sinon, il lance le client système `ssh` via `proc_open()`. Dans les deux cas, il exécute `git-upload-pack` ou `git-receive-pack` sur le serveur distant.

```php
use Pitmaster\Protocol\SshClient;

$client = new SshClient();
```

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

Aucune extension n’est nécessaire. Les deux méthodes fonctionnent différemment :

**Client système `ssh`** (utilisé lorsque `ssh2` n’est pas chargé). Pitmaster exécute `ssh -o BatchMode=yes -o ConnectTimeout=30 -p <port> <user>@<host> <command>` ; l’authentification et la vérification de la clé hôte suivent donc votre configuration SSH et votre agent. Ces variables d’environnement modifient la commande :

| Variable | Effet |
|----------|--------|
| `PITMASTER_SSH_COMMAND` | Exécutable à lancer à la place de `ssh` |
| `PITMASTER_SSH_IDENTITY_FILE` | Transmis comme `-i <file>` |
| `PITMASTER_SSH_KNOWN_HOSTS` | Transmis comme `-o UserKnownHostsFile=<file>` |
| `PITMASTER_SSH_STRICT_HOST_KEY_CHECKING` | Transmis comme `-o StrictHostKeyChecking=<value>` |

Cette méthode lance un processus ; elle n’est donc pas disponible sur les handles ouverts avec `['processes' => false]`.

**Extension `ssh2`** (toujours privilégiée lorsqu’elle est chargée). Pitmaster s’authentifie avec `~/.ssh/id_rsa`, puis avec `~/.ssh/id_ed25519` si la clé RSA est présente mais refusée, et enfin avec l’agent SSH. Les variables `PITMASTER_SSH_*` sont ignorées, et la clé hôte du serveur n’est pas vérifiée avec cette méthode ([#22](https://github.com/inline0/pitmaster/issues/22)).

Le transport SSH exécute `git-upload-pack` ou `git-receive-pack` comme commande distante et communique sur le canal SSH avec le même protocole pkt-line que HTTP intelligent.

## Protocole Git (TCP)

Le protocole git natif communique via le port TCP 9418 au moyen de sockets PHP. `GitProtocolClient` implémente la découverte des références et `upload-pack` (récupération) ; il ne peut pas envoyer de modifications. `clone()` et `fetch()` ne dirigent pas les URL `git://` vers ce protocole ; utilisez donc directement le client.

```php
use Pitmaster\Protocol\GitProtocolClient;

$client = new GitProtocolClient();
```

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

Caractéristiques :
- Aucune authentification (en pratique, lecture seule)
- Aucun chiffrement
- Abandonné par la plupart des fournisseurs d’hébergement
- Utilise le même cadrage pkt-line que HTTP intelligent

Le protocole git envoie le nom du service et le chemin du dépôt dans la requête initiale, puis passe à la découverte des références pkt-line standard et à la négociation du pack.

## Bundles

Les bundles Git sont des fichiers pack hors ligne contenant les informations de référence. Ils permettent de transférer les données d’un dépôt sans connexion réseau.

```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 lit les en-têtes de bundle v2 et v3. Il n’existe pas de méthode `Repository` pour importer un bundle : écrivez `packData()` dans `.git/objects/pack/`, créez son index avec `PackIndexer::writeIndex()`, puis mettez vous-même les références à jour.

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

Les bundles sont utiles pour :
- Les transferts par support amovible (clés USB)
- Les sauvegardes incrémentielles
- Préparer des clones dans des environnements isolés du réseau

## Clonages superficiels

Pitmaster prend en charge les clonages superficiels, qui ne récupèrent qu’une profondeur limitée de l’historique des commits.

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

Passez une profondeur à `Pitmaster::clone($url, $path, $depth)` ou `$repo->fetch($remote, $depth)`. La requête ajoute la capacité `shallow` et une ligne `deepen` :
```
want <hash>
deepen <depth>
```

Le serveur répond avec des lignes `shallow <hash>` qui indiquent où l’historique a été tronqué. Pitmaster calcule la limite superficielle à partir de la profondeur elle-même et utilise les lignes `shallow` du serveur lorsque ce calcul ne trouve rien ; le résultat est stocké dans `.git/shallow`. `ShallowClone::readShallow()`, `writeShallow()` et `isShallow()` utilisent directement ce fichier.

## Comparaison des protocoles

| Protocole | Authentification | Chiffrement | Envoi | Utilisation typique |
|----------|------|-----------|------|-------------|
| Smart HTTP | Identifiants dans URL | HTTPS | Oui | Transport principal |
| Dumb HTTP | Identifiants dans URL | HTTPS | Non | Solution de repli héritée |
| SSH | Clés SSH ou agent | SSH | Oui | Dépôts privés, CI |
| Git (TCP) | Aucun | Aucun | Non | Miroirs en lecture seule |
| Bundle | S.O. | S.O. | S.O. | Transfert hors ligne |

## Sélection du transport

`Pitmaster::clone()`, `$repo->fetch()` et `$repo->push()` sélectionnent le transport à partir de URL :

| Modèle URL | Transport |
|------------|-----------|
| `ssh://...` | SSH |
| `user@host:path` | SSH |
| Tout autre (`https://...`, `http://...`) | Smart HTTP ; clone et fetch basculent vers dumb HTTP |

Les URL `git://` et les chemins locaux ne sont pas pris en charge par ces méthodes : ils sont transmis au client smart HTTP et échouent. Utilisez directement `GitProtocolClient` pour `git://`. Un HTTPS URL contenant à la fois un utilisateur et un port (`https://user@host:8443/repo.git`) est actuellement pris à tort pour un SSH URL ([#17](https://github.com/inline0/pitmaster/issues/17)).
