
# Protocolos

Pitmaster admite varios protocolos de transporte de red para comunicarse con servidores git. HTTP inteligente es el transporte principal. Hay protocolos adicionales para ofrecer mayor compatibilidad.

## HTTP inteligente (principal)

Es el transporte recomendado. Funciona sobre HTTPS y es el protocolo más extendido. No hay API para encabezados personalizados o credenciales; estas solo se pueden pasar en URL (`https://user:token@host/repo.git`), que PHP envía como autenticación básica. `clone()` almacena URL, incluidas las credenciales, como `remote.origin.url` en `.git/config`. Las solicitudes usan los contenedores de flujo de PHP, por lo que debe estar habilitado `allow_url_fopen`.

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Consulte [HTTP inteligente](https://pitmaster.inline0.dev/es/docs/network/smart-http) para obtener todos los detalles.

### Protocolo v1

El protocolo tradicional HTTP inteligente. Todas las referencias se envían durante el descubrimiento y la negociación usa líneas want/have/done.

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

### Protocolo v2

El protocolo más reciente, con comandos estructurados (`ls-refs`, `fetch`). Es más eficiente para repositorios con muchas referencias porque el cliente puede filtrar la lista.

`clone()` y `fetch()` siempre usan el protocolo v1. El protocolo v2 está disponible explícitamente sobre HTTP inteligente a través de `SmartHttpClient::discoverRefsV2()` y `UploadPackClient::fetchV2()`.

## HTTP simple

Alternativa para servidores que no admiten el protocolo HTTP inteligente. El protocolo simple obtiene objetos y paquetes individualmente mediante solicitudes GET de HTTP sin formato.

```php
use Pitmaster\Protocol\DumbHttpClient;

$client = new DumbHttpClient();
```

Limitaciones de HTTP simple:
- Sin negociación (el cliente debe descargarlo todo)
- Sin compresión delta durante la transferencia
- Mucho más lento que HTTP inteligente
- Algunos servidores (GitHub, GitLab) no lo admiten

El protocolo simple obtiene:
1. `GET /info/refs` (texto sin formato, sin pkt-line)
2. `GET /HEAD` (rama predeterminada)
3. `GET /objects/info/packs` (lista de paquetes disponibles)
4. `GET /objects/pack/pack-<hash>.pack` y `.idx` (cada paquete enumerado y su índice)
5. `GET /objects/<xx>/<rest>` (objetos sueltos individuales, recorridos desde las puntas de las referencias)

El paso 5 solo se ejecuta cuando el servidor no enumera paquetes. Si enumera paquetes, no se descargan los objetos que solo existen como archivos sueltos en el servidor ([#18](https://github.com/inline0/pitmaster/issues/18)). El cliente simple solo admite ID de objeto de 40 caracteres (SHA-1). `clone()` y `fetch()` recurren a HTTP simple cuando falla el intercambio HTTP inteligente.

## SSH

El transporte SSH usa la extensión `ssh2` PHP cuando está cargada. De lo contrario, inicia el cliente `ssh` del sistema mediante `proc_open()`. En ambos casos ejecuta `git-upload-pack` o `git-receive-pack` en el remoto.

```php
use Pitmaster\Protocol\SshClient;

$client = new SshClient();
```

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

No se requiere ninguna extensión. Las dos vías funcionan de manera diferente:

**Cliente `ssh` del sistema** (se usa cuando `ssh2` no está cargado). Pitmaster ejecuta `ssh -o BatchMode=yes -o ConnectTimeout=30 -p <port> <user>@<host> <command>`, por lo que la autenticación y la comprobación de la clave del host siguen la configuración de SSH y su agente. Estas variables de entorno ajustan el comando:

| Variable | Efecto |
|----------|--------|
| `PITMASTER_SSH_COMMAND` | Ejecutable que se ejecutará en lugar de `ssh` |
| `PITMASTER_SSH_IDENTITY_FILE` | Se pasa como `-i <file>` |
| `PITMASTER_SSH_KNOWN_HOSTS` | Se pasa como `-o UserKnownHostsFile=<file>` |
| `PITMASTER_SSH_STRICT_HOST_KEY_CHECKING` | Se pasa como `-o StrictHostKeyChecking=<value>` |

Esta vía inicia un proceso, así que no está disponible en identificadores abiertos con `['processes' => false]`.

**Extensión `ssh2`** (siempre se prefiere cuando está cargada). Pitmaster se autentica con `~/.ssh/id_rsa` y, si la clave RSA está presente pero se rechaza, con `~/.ssh/id_ed25519`; en los demás casos, usa el agente SSH. Se ignoran las variables `PITMASTER_SSH_*` y, por esta vía, no se verifica la clave del host del servidor ([#22](https://github.com/inline0/pitmaster/issues/22)).

El transporte SSH ejecuta `git-upload-pack` o `git-receive-pack` como comando remoto y se comunica por el canal SSH mediante el mismo protocolo pkt-line que HTTP inteligente.

## Protocolo Git (TCP)

El protocolo nativo de git se comunica por el puerto TCP 9418 mediante sockets PHP. `GitProtocolClient` implementa el descubrimiento de referencias y `upload-pack` (obtención); no puede enviar cambios. `clone()` y `fetch()` no dirigen las URL `git://` hacia este protocolo, así que use el cliente directamente.

```php
use Pitmaster\Protocol\GitProtocolClient;

$client = new GitProtocolClient();
```

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

Características:
- Sin autenticación (en la práctica, solo lectura)
- Sin cifrado
- La mayoría de los proveedores de alojamiento lo han desaprobado
- Usa el mismo encuadre pkt-line que HTTP inteligente

El protocolo git envía el nombre del servicio y la ruta del repositorio como solicitud inicial; luego continúa con el descubrimiento de referencias pkt-line estándar y la negociación del paquete.

## Paquetes de transferencia

Los paquetes de transferencia Git son archivos de paquete sin conexión que contienen información de referencias. Permiten transferir datos del repositorio sin conexión de red.

```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 lee encabezados de paquetes de transferencia v2 y v3. No hay ningún método `Repository` para importar un paquete de transferencia: escriba `packData()` en `.git/objects/pack/`, cree su índice con `PackIndexer::writeIndex()` y actualice las referencias por su cuenta.

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

Los paquetes de transferencia son útiles para:
- Transferencias mediante dispositivos físicos (unidades USB)
- Copias de seguridad incrementales
- Preparar clones en entornos aislados de la red

## Clones superficiales

Pitmaster admite clones superficiales, que solo obtienen una parte limitada del historial de confirmaciones.

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

Pase una profundidad a `Pitmaster::clone($url, $path, $depth)` o `$repo->fetch($remote, $depth)`. La solicitud añade la capacidad `shallow` y una línea `deepen`:
```
want <hash>
deepen <depth>
```

El servidor responde con `shallow <hash>` líneas que indican dónde se truncó el historial. Pitmaster calcula el límite superficial a partir de la profundidad y usa las líneas `shallow` del servidor cuando el cálculo no encuentra ninguna; el resultado se almacena en `.git/shallow`. `ShallowClone::readShallow()`, `writeShallow()` y `isShallow()` trabajan directamente con ese archivo.

## Comparación de protocolos

| Protocolo | Autenticación | Cifrado | Envío | Uso habitual |
|----------|------|-----------|------|-------------|
| Smart HTTP | Credenciales en URL | HTTPS | Sí | Transporte principal |
| Dumb HTTP | Credenciales en URL | HTTPS | No | Alternativa heredada |
| SSH | Claves SSH o agente | SSH | Sí | Repositorios privados, CI |
| Git (TCP) | Ninguna | Ninguno | No | Réplicas de solo lectura |
| Bundle | N/A | N/A | N/A | Transferencia sin conexión |

## Selección del transporte

`Pitmaster::clone()`, `$repo->fetch()` y `$repo->push()` seleccionan el transporte a partir de URL:

| Patrón URL | Transporte |
|------------|-----------|
| `ssh://...` | SSH |
| `user@host:path` | SSH |
| Cualquier otro (`https://...`, `http://...`) | Smart HTTP; clone y fetch recurren a dumb HTTP |

`git://` no admite URL ni rutas locales con estos métodos: se envían al cliente smart HTTP y fallan. Usa `GitProtocolClient` directamente para `git://`. Actualmente, un HTTPS URL que contiene tanto un usuario como un puerto (`https://user@host:8443/repo.git`) se confunde con un SSH URL ([#17](https://github.com/inline0/pitmaster/issues/17)).
