
# Protocolli

Pitmaster supporta diversi protocolli di trasporto di rete per comunicare con i server git. Smart HTTP è il trasporto principale. Sono disponibili protocolli aggiuntivi per una compatibilità più ampia.

## Smart HTTP (principale)

Il trasporto consigliato. Funziona su HTTPS ed è il protocollo più diffuso. Non esiste API per intestazioni personalizzate o credenziali; le credenziali possono essere passate solo in URL (`https://user:token@host/repo.git`), che PHP invia come autenticazione Basic. `clone()` memorizza URL, credenziali incluse, come `remote.origin.url` in `.git/config`. Le richieste usano i wrapper di stream di PHP, quindi `allow_url_fopen` deve essere abilitato.

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Per tutti i dettagli, consultate [Smart HTTP](https://pitmaster.inline0.dev/it/docs/network/smart-http).

### Protocollo v1

Il protocollo smart HTTP tradizionale. Durante il rilevamento vengono inviati tutti i riferimenti e la negoziazione usa le righe want/have/done.

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

### Protocollo v2

Il protocollo più recente, con comandi strutturati (`ls-refs`, `fetch`). Più efficiente per i repository con molti riferimenti, perché il client può filtrare l'elenco.

`clone()` e `fetch()` usano sempre il protocollo v1. Il protocollo v2 è disponibile esplicitamente tramite smart HTTP con `SmartHttpClient::discoverRefsV2()` e `UploadPackClient::fetchV2()`.

## HTTP non smart

Alternativa per i server che non supportano il protocollo smart HTTP. Il protocollo non smart recupera singolarmente oggetti e pack tramite semplici richieste GET HTTP.

```php
use Pitmaster\Protocol\DumbHttpClient;

$client = new DumbHttpClient();
```

Limitazioni di HTTP non smart:
- Nessuna negoziazione (il client deve scaricare tutto)
- Nessuna compressione delta durante il trasferimento
- Notevolmente più lento di HTTP smart
- Alcuni server (GitHub, GitLab) non lo supportano

Il protocollo non smart recupera:
1. `GET /info/refs` (testo semplice, senza pkt-line)
2. `GET /HEAD` (branch predefinito)
3. `GET /objects/info/packs` (elenco dei pack disponibili)
4. `GET /objects/pack/pack-<hash>.pack` e `.idx` (ogni pack elencato e il relativo indice)
5. `GET /objects/<xx>/<rest>` (singoli oggetti sciolti, a partire dalle estremità dei riferimenti)

Il passaggio 5 viene eseguito solo quando il server non elenca pack. Se invece ne elenca, gli oggetti presenti solo come file sciolti sul server non vengono scaricati ([#18](https://github.com/inline0/pitmaster/issues/18)). Il client non smart accetta solo ID oggetto di 40 caratteri (SHA-1). `clone()` e `fetch()` passano al protocollo HTTP non smart quando lo scambio smart HTTP fallisce.

## SSH

Il trasporto SSH usa l'estensione `ssh2` PHP quando è caricata. Altrimenti avvia il client di sistema `ssh` tramite `proc_open()`. In entrambi i casi esegue `git-upload-pack` o `git-receive-pack` sul remote.

```php
use Pitmaster\Protocol\SshClient;

$client = new SshClient();
```

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

Non è necessaria alcuna estensione. I due percorsi funzionano in modo diverso:

**Client di sistema `ssh`** (usato quando `ssh2` non è caricato). Pitmaster esegue `ssh -o BatchMode=yes -o ConnectTimeout=30 -p <port> <user>@<host> <command>`, quindi l'autenticazione e la verifica della chiave host seguono la configurazione SSH e l'agent in uso. Queste variabili d'ambiente modificano il comando:

| Variabile | Effetto |
|----------|--------|
| `PITMASTER_SSH_COMMAND` | Eseguibile da usare al posto di `ssh` |
| `PITMASTER_SSH_IDENTITY_FILE` | Passato come `-i <file>` |
| `PITMASTER_SSH_KNOWN_HOSTS` | Passato come `-o UserKnownHostsFile=<file>` |
| `PITMASTER_SSH_STRICT_HOST_KEY_CHECKING` | Passato come `-o StrictHostKeyChecking=<value>` |

Questo percorso avvia un processo, quindi non è disponibile sugli handle aperti con `['processes' => false]`.

**Estensione `ssh2`** (sempre preferita quando è caricata). Pitmaster esegue l'autenticazione con `~/.ssh/id_rsa`, poi con `~/.ssh/id_ed25519` se la chiave RSA è presente ma viene rifiutata, e in caso contrario con l'agent SSH. Le variabili `PITMASTER_SSH_*` vengono ignorate e, in questo percorso, la chiave host del server non viene verificata ([#22](https://github.com/inline0/pitmaster/issues/22)).

Il trasporto SSH esegue `git-upload-pack` o `git-receive-pack` come comando remoto e comunica sul canale SSH usando lo stesso protocollo pkt-line di HTTP smart.

## Protocollo Git (TCP)

Il protocollo nativo git comunica sulla porta TCP 9418 usando socket PHP. `GitProtocolClient` implementa il rilevamento dei riferimenti e `upload-pack` (fetch); non può eseguire push. `clone()` e `fetch()` non instradano gli URL `git://` verso di esso, quindi usate direttamente il client.

```php
use Pitmaster\Protocol\GitProtocolClient;

$client = new GitProtocolClient();
```

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

Caratteristiche:
- Nessuna autenticazione (in pratica, sola lettura)
- Nessuna crittografia
- Dichiarato obsoleto dalla maggior parte dei provider di hosting
- Usa la stessa struttura pkt-line di HTTP smart

Il protocollo git invia il nome del servizio e il percorso del repository come richiesta iniziale, quindi procede con il rilevamento dei riferimenti e la negoziazione del pack standard basati su pkt-line.

## Bundle

I bundle Git sono file pack offline contenenti informazioni sui riferimenti. Permettono di trasferire i dati di un repository senza una connessione di rete.

```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 legge le intestazioni dei bundle v2 e v3. Non esiste un metodo `Repository` per importare un bundle: scrivete `packData()` in `.git/objects/pack/`, create l'indice con `PackIndexer::writeIndex()` e aggiornate i riferimenti manualmente.

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

I bundle sono utili per:
- Trasferimenti tramite supporti fisici (unità USB)
- Backup incrementali
- Preparare cloni in ambienti isolati dalla rete

## Cloni superficiali

Pitmaster supporta i cloni superficiali, che recuperano solo un numero limitato di commit nella cronologia.

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

Passate una profondità a `Pitmaster::clone($url, $path, $depth)` o `$repo->fetch($remote, $depth)`. La richiesta aggiunge la funzionalità `shallow` e una riga `deepen`:
```
want <hash>
deepen <depth>
```

Il server risponde con righe `shallow <hash>` che indicano dove è stata troncata la cronologia. Pitmaster calcola il limite della cronologia a partire dalla profondità e usa le righe `shallow` del server quando il calcolo non produce risultati; il risultato viene salvato in `.git/shallow`. `ShallowClone::readShallow()`, `writeShallow()` e `isShallow()` lavorano direttamente con quel file.

## Confronto dei protocolli

| Protocollo | Autenticazione | Crittografia | Push | Uso tipico |
|----------|------|-----------|------|-------------|
| HTTP smart | Credenziali in URL | HTTPS | Sì | Trasporto principale |
| HTTP non smart | Credenziali in URL | HTTPS | No | Alternativa legacy |
| SSH | Chiavi SSH o agent | SSH | Sì | Repository privati, CI |
| Git (TCP) | Nessuna | Nessuna | No | Mirror in sola lettura |
| Bundle | N/D | N/D | N/D | Trasferimento offline |

## Selezione del trasporto

`Pitmaster::clone()`, `$repo->fetch()` e `$repo->push()` selezionano il trasporto in base a URL:

| Schema URL | Trasporto |
|------------|-----------|
| `ssh://...` | SSH |
| `user@host:path` | SSH |
| Qualsiasi altro (`https://...`, `http://...`) | HTTP smart; clone e fetch passano a HTTP non smart |

Gli URL `git://` e i percorsi locali non sono supportati da questi metodi: vengono inviati al client HTTP smart e falliscono. Per `git://` usate direttamente `GitProtocolClient`. Un HTTPS URL che contiene sia un utente sia una porta (`https://user@host:8443/repo.git`) viene attualmente interpretato erroneamente come SSH URL ([#17](https://github.com/inline0/pitmaster/issues/17)).
