
# Protocolos

Pitmaster é compatível com vários protocolos de transporte de rede para comunicação com servidores git. Smart HTTP é o transporte principal. Há protocolos adicionais para maior compatibilidade.

## Smart HTTP (principal)

O transporte recomendado. Funciona por HTTPS e é o protocolo mais amplamente implantado. Não há API para cabeçalhos ou credenciais personalizados; as credenciais só podem ser passadas em URL (`https://user:token@host/repo.git`), que PHP envia como autenticação Basic. `clone()` armazena URL, incluindo as credenciais, como `remote.origin.url` em `.git/config`. As solicitações usam os wrappers de stream de PHP, portanto `allow_url_fopen` precisa estar habilitado.

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Consulte [Smart HTTP](https://pitmaster.inline0.dev/pt/docs/network/smart-http) para ver todos os detalhes.

### Protocolo v1

O protocolo smart HTTP tradicional. Todas as refs são enviadas durante a descoberta, e a negociação usa linhas want/have/done.

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

### Protocolo v2

O protocolo mais novo, com comandos estruturados (`ls-refs`, `fetch`). É mais eficiente para repositórios com muitas refs, pois o cliente pode filtrar a lista de refs.

`clone()` e `fetch()` sempre usam o protocolo v1. O protocolo v2 está disponível explicitamente por smart HTTP via `SmartHttpClient::discoverRefsV2()` e `UploadPackClient::fetchV2()`.

## Dumb HTTP

Alternativa para servidores que não são compatíveis com o protocolo smart HTTP. O protocolo dumb busca objetos e packs individualmente por solicitações GET simples de HTTP.

```php
use Pitmaster\Protocol\DumbHttpClient;

$client = new DumbHttpClient();
```

Limitações do dumb HTTP:
- Sem negociação (o cliente precisa baixar tudo)
- Sem compressão delta durante a transferência
- Significativamente mais lento que smart HTTP
- Alguns servidores (GitHub, GitLab) não são compatíveis

O protocolo dumb busca:
1. `GET /info/refs` (texto simples, sem pkt-line)
2. `GET /HEAD` (branch padrão)
3. `GET /objects/info/packs` (lista de packs disponíveis)
4. `GET /objects/pack/pack-<hash>.pack` e `.idx` (cada pack listado e seu índice)
5. `GET /objects/<xx>/<rest>` (objetos soltos individuais, percorridos a partir das pontas das refs)

A etapa 5 só é executada quando o servidor não lista nenhum pack. Quando há packs listados, objetos que existem apenas como arquivos soltos no servidor não são baixados ([#18](https://github.com/inline0/pitmaster/issues/18)). O cliente dumb aceita apenas IDs de objeto de 40 caracteres (SHA-1). `clone()` e `fetch()` recorrem ao dumb HTTP quando a troca pelo smart HTTP falha.

## SSH

O transporte SSH usa a extensão `ssh2` PHP quando ela está carregada. Caso contrário, inicia o cliente `ssh` do sistema por meio de `proc_open()`. Em ambos os casos, executa `git-upload-pack` ou `git-receive-pack` no remoto.

```php
use Pitmaster\Protocol\SshClient;

$client = new SshClient();
```

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

Nenhuma extensão é necessária. Os dois caminhos se comportam de forma diferente:

**Cliente `ssh` do sistema** (usado quando `ssh2` não está carregado). Pitmaster executa `ssh -o BatchMode=yes -o ConnectTimeout=30 -p <port> <user>@<host> <command>`, então a autenticação e a verificação da chave do host seguem a configuração de SSH e o agente. Estas variáveis de ambiente ajustam o comando:

| Variável | Efeito |
|----------|--------|
| `PITMASTER_SSH_COMMAND` | Executável a ser usado em vez de `ssh` |
| `PITMASTER_SSH_IDENTITY_FILE` | Passado como `-i <file>` |
| `PITMASTER_SSH_KNOWN_HOSTS` | Passado como `-o UserKnownHostsFile=<file>` |
| `PITMASTER_SSH_STRICT_HOST_KEY_CHECKING` | Passado como `-o StrictHostKeyChecking=<value>` |

Este caminho inicia um processo, portanto não está disponível em handles abertos com `['processes' => false]`.

**Extensão `ssh2`** (sempre preferida quando carregada). Pitmaster autentica com `~/.ssh/id_rsa`, depois com `~/.ssh/id_ed25519` se a chave RSA estiver presente, mas for rejeitada, e caso contrário com o agente SSH. As variáveis `PITMASTER_SSH_*` são ignoradas, e a chave do host do servidor não é verificada neste caminho ([#22](https://github.com/inline0/pitmaster/issues/22)).

O transporte SSH executa `git-upload-pack` ou `git-receive-pack` como comando remoto e se comunica pelo canal SSH usando o mesmo protocolo pkt-line do smart HTTP.

## Protocolo Git (TCP)

O protocolo nativo git se comunica pela porta TCP 9418 usando sockets PHP. `GitProtocolClient` implementa a descoberta de refs e `upload-pack` (fetch); não pode fazer push. `clone()` e `fetch()` não encaminham URLs `git://` para esse protocolo, então use o cliente diretamente.

```php
use Pitmaster\Protocol\GitProtocolClient;

$client = new GitProtocolClient();
```

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

Características:
- Sem autenticação (na prática, somente leitura)
- Sem criptografia
- Descontinuado pela maioria dos provedores de hospedagem
- Usa o mesmo enquadramento pkt-line do smart HTTP

O protocolo git envia o nome do serviço e o caminho do repositório como solicitação inicial e, em seguida, prossegue com a descoberta de refs padrão pkt-line e a negociação do pack.

## Bundles

Os bundles Git são arquivos de pack off-line com informações de refs. Eles permitem transferir dados do repositório sem uma conexão de rede.

```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 lê cabeçalhos de bundle v2 e v3. Não há um método `Repository` para importar um bundle: grave `packData()` em `.git/objects/pack/`, crie seu índice com `PackIndexer::writeIndex()` e atualize as refs por conta própria.

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

Os bundles são úteis para:
- Transferências por sneaker net (unidades USB)
- Backups incrementais
- Preparar clones em ambientes isolados de redes

## Clones rasos

Pitmaster oferece suporte a clones rasos, que buscam apenas uma profundidade limitada do histórico de commits.

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

Passe uma profundidade para `Pitmaster::clone($url, $path, $depth)` ou `$repo->fetch($remote, $depth)`. A solicitação adiciona o recurso `shallow` e uma linha `deepen`:
```
want <hash>
deepen <depth>
```

O servidor responde com linhas `shallow <hash>` que indicam onde o histórico foi truncado. Pitmaster calcula o limite superficial com base na própria profundidade e usa as linhas `shallow` do servidor quando esse cálculo não encontra nada; o resultado é armazenado em `.git/shallow`. `ShallowClone::readShallow()`, `writeShallow()` e `isShallow()` trabalham diretamente com esse arquivo.

## Comparação de protocolos

| Protocolo | Autenticação | Criptografia | Push | Uso típico |
|----------|------|-----------|------|-------------|
| Smart HTTP | Credenciais em URL | HTTPS | Sim | Transporte principal |
| Dumb HTTP | Credenciais em URL | HTTPS | Não | Alternativa legada |
| SSH | chaves ou agente SSH | SSH | Sim | Repositórios privados, CI |
| Git (TCP) | Nenhuma | Nenhuma | Não | Espelhos somente leitura |
| Bundle | N/A | N/A | N/A | Transferência off-line |

## Seleção de transporte

`Pitmaster::clone()`, `$repo->fetch()` e `$repo->push()` selecionam o transporte a partir de URL:

| Padrão URL | Transporte |
|------------|-----------|
| `ssh://...` | SSH |
| `user@host:path` | SSH |
| Qualquer outro (`https://...`, `http://...`) | Smart HTTP; clone e fetch recorrem ao dumb HTTP |

URLs `git://` e caminhos locais não são compatíveis com esses métodos: eles são enviados ao cliente smart HTTP e falham. Use `GitProtocolClient` diretamente para `git://`. Um HTTPS URL que contém usuário e porta (`https://user@host:8443/repo.git`) é atualmente confundido com um SSH URL ([#17](https://github.com/inline0/pitmaster/issues/17)).
