
# Protokollat

Pitmaster tukee useita verkkosiirtoprotokollia git-palvelinten kanssa viestimiseen. Älykäs HTTP on ensisijainen siirtotapa. Muita protokollia voi käyttää paremman yhteensopivuuden saavuttamiseksi.

## Älykäs HTTP (ensisijainen)

Suositeltu siirtotapa. Toimii HTTPS-yhteyden kautta ja on laajimmin käytössä oleva protokolla. Mukautetuille otsakkeille tai tunnistetiedoille ei ole API-toimintoa; tunnistetiedot voi välittää vain URL-kentässä (`https://user:token@host/repo.git`), jonka PHP lähettää Basic-todennuksena. `clone()` tallentaa URL-arvon tunnistetietoineen muodossa `remote.origin.url` kohteeseen `.git/config`. Pyynnöissä käytetään PHP-virtojen käsittelijöitä, joten `allow_url_fopen` on otettava käyttöön.

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Katso [Älykäs HTTP](https://pitmaster.inline0.dev/fi/docs/network/smart-http) saadaksesi lisätietoja.

### Protokolla v1

Perinteinen älykäs HTTP-protokolla. Kaikki viitteet lähetetään selvityksen aikana, ja neuvottelussa käytetään want/have/done-rivejä.

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

### Protokolla v2

Uudempi protokolla, jossa käytetään rakenteisia komentoja (`ls-refs`, `fetch`). Tehokkaampi tietovarastoissa, joissa on paljon viitteitä, koska asiakas voi suodattaa viiteluetteloa.

`clone()` ja `fetch()` käyttävät aina protokollaa v1. Protokolla v2 on käytettävissä erikseen älykkään HTTP-protokollan kautta valitsimilla `SmartHttpClient::discoverRefsV2()` ja `UploadPackClient::fetchV2()`.

## Yksinkertainen HTTP

Varaprotokolla palvelimille, jotka eivät tue älykästä HTTP-protokollaa. Yksinkertaisessa protokollassa objektit ja paketit noudetaan yksitellen tavallisilla HTTP GET-pyynnöillä.

```php
use Pitmaster\Protocol\DumbHttpClient;

$client = new DumbHttpClient();
```

Yksinkertaisen HTTP-protokollan rajoitukset:
- Ei neuvottelua (asiakkaan on ladattava kaikki)
- Siirron aikana ei tehdä delta-pakkausta
- Huomattavasti hitaampi kuin älykäs HTTP
- Jotkin palvelimet (GitHub, GitLab) eivät tue sitä

Yksinkertainen protokolla noutaa seuraavat:
1. `GET /info/refs` (pelkkää tekstiä, ei pkt-line-muotoa)
2. `GET /HEAD` (oletushaara)
3. `GET /objects/info/packs` (luettelo saatavilla olevista paketeista)
4. `GET /objects/pack/pack-<hash>.pack` ja `.idx` (jokainen luettelossa oleva paketti ja sen indeksi)
5. `GET /objects/<xx>/<rest>` (yksittäiset irralliset objektit, joita käydään läpi viitteiden kärjistä)

Vaihe 5 suoritetaan vain, kun palvelin ei ilmoita paketteja. Jos palvelin ilmoittaa paketit, palvelimella vain irrallisina tiedostoina olevia objekteja ei ladata ([#18](https://github.com/inline0/pitmaster/issues/18)). Yksinkertainen asiakas hyväksyy vain 40 merkin pituisia (SHA-1) objektitunnisteita. `clone()` ja `fetch()` siirtyvät yksinkertaiseen HTTP-protokollaan, jos älykäs HTTP-tiedonsiirto epäonnistuu.

## SSH

SSH-siirrossa käytetään `ssh2`-laajennusta PHP, jos se on ladattu. Muussa tapauksessa järjestelmän `ssh`-asiakas käynnistetään valitsimella `proc_open()`. Kummassakin tapauksessa etäpalvelimessa suoritetaan `git-upload-pack` tai `git-receive-pack`.

```php
use Pitmaster\Protocol\SshClient;

$client = new SshClient();
```

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

Laajennusta ei tarvita. Nämä kaksi tapaa toimivat eri tavoin:

**Järjestelmän `ssh`-asiakas** (käytetään, kun `ssh2` ei ole ladattu). Pitmaster suorittaa komennon `ssh -o BatchMode=yes -o ConnectTimeout=30 -p <port> <user>@<host> <command>`, joten todennus ja isäntäavaimen tarkistus noudattavat SSH-määritystäsi ja agenttiasi. Nämä ympäristömuuttujat muokkaavat komentoa:

| Muuttuja | Vaikutus |
|----------|--------|
| `PITMASTER_SSH_COMMAND` | Suoritettava ohjelma `ssh`-ohjelman sijaan |
| `PITMASTER_SSH_IDENTITY_FILE` | Välitetään muodossa `-i <file>` |
| `PITMASTER_SSH_KNOWN_HOSTS` | Välitetään muodossa `-o UserKnownHostsFile=<file>` |
| `PITMASTER_SSH_STRICT_HOST_KEY_CHECKING` | Välitetään muodossa `-o StrictHostKeyChecking=<value>` |

Tässä tavassa käynnistetään prosessi, joten se ei ole käytettävissä kahvoissa, jotka on avattu valitsimella `['processes' => false]`.

**`ssh2`-laajennus** (aina ensisijainen, kun ladattu). Pitmaster todentaa ensin `~/.ssh/id_rsa`-avaimella, sitten `~/.ssh/id_ed25519`-avaimella, jos RSA-avain on olemassa mutta se hylätään, ja muussa tapauksessa SSH-agentilla. `PITMASTER_SSH_*`-muuttujat ohitetaan, eikä palvelimen isäntäavainta tarkisteta tällä tavalla ([#22](https://github.com/inline0/pitmaster/issues/22)).

SSH-siirrossa suoritetaan `git-upload-pack` tai `git-receive-pack` etäkomentona ja viestitään SSH-kanavan kautta käyttäen samaa pkt-line-protokollaa kuin älykkäässä HTTP-protokollassa.

## Git-protokolla (TCP)

Natiivi git-protokolla viestii TCP-portissa 9418 käyttämällä PHP-socket-yhteyksiä. `GitProtocolClient` toteuttaa viitteiden selvityksen ja `upload-pack`-toiminnon (noutamisen); sillä ei voi lähettää. `clone()` ja `fetch()` eivät ohjaa `git://`-URL-osoitteita siihen, joten käytä asiakasta suoraan.

```php
use Pitmaster\Protocol\GitProtocolClient;

$client = new GitProtocolClient();
```

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

Ominaisuudet:
- Ei todennusta (käytännössä vain luku)
- Ei salausta
- Useimmat palveluntarjoajat ovat poistaneet käytöstä
- Käyttää samaa pkt-line-kehystystä kuin älykäs HTTP

git-protokolla lähettää palvelun nimen ja tietovaraston polun ensimmäisessä pyynnössä ja jatkaa sitten tavallisella pkt-line-viitteiden selvityksellä ja pakettien neuvottelulla.

## Pakettiluettelot

Git-pakettiluettelot ovat offline-pakettitiedostoja, jotka sisältävät viitetiedot. Niiden avulla tietovaraston tietoja voi siirtää ilman verkkoyhteyttä.

```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 lukee v2- ja v3-pakettiluettelon otsakkeet. Pakettiluettelon tuomiseen ei ole `Repository`-menetelmää: kirjoita `packData()` kohteeseen `.git/objects/pack/`, luo sen indeksi valitsimella `PackIndexer::writeIndex()` ja päivitä viitteet itse.

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

Pakettiluetteloista on hyötyä seuraavissa:
- Tietojen siirto USB-asemilla
- Lisävarmuuskopiot
- Kloonausten alustaminen eristetyissä ympäristöissä

## Vajaat kloonaukset

Pitmaster tukee vajaita kloonauksia, joissa noudetaan vain rajallinen määrä commit-historiaa.

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

Anna syvyys valitsimelle `Pitmaster::clone($url, $path, $depth)` tai `$repo->fetch($remote, $depth)`. Pyyntöön lisätään `shallow`-ominaisuus ja `deepen`-rivi:
```
want <hash>
deepen <depth>
```

Palvelin vastaa `shallow <hash>`-riveillä, jotka ilmaisevat, missä kohtaa historia katkaistiin. Pitmaster laskee vajaan historian rajan syvyydestä ja käyttää palvelimen `shallow`-rivejä, jos laskenta ei löydä sitä; tulos tallennetaan kohteeseen `.git/shallow`. `ShallowClone::readShallow()`, `writeShallow()` ja `isShallow()` käsittelevät tätä tiedostoa suoraan.

## Protokollien vertailu

| Protokolla | Todennus | Salaus | Lähetys | Tyypillinen käyttö |
|----------|------|-----------|------|-------------|
| Älykäs HTTP | Tunnistetiedot kentässä URL | HTTPS | Kyllä | Ensisijainen siirtotapa |
| Yksinkertainen HTTP | Tunnistetiedot kentässä URL | HTTPS | Ei | Vanha varaprotokolla |
| SSH | SSH-avaimet tai agentti | SSH | Kyllä | Yksityiset tietovarastot, CI |
| Git (TCP) | Ei mitään | Ei mitään | Ei | Vain luku -peilipalvelimet |
| Paketti | Ei sovellu | Ei sovellu | Ei sovellu | Offline-siirto |

## Siirtotavan valinta

`Pitmaster::clone()`, `$repo->fetch()` ja `$repo->push()` valitsevat siirtotavan kohteen URL perusteella:

| URL-malli | Siirtotapa |
|------------|-----------|
| `ssh://...` | SSH |
| `user@host:path` | SSH |
| Kaikki muut (`https://...`, `http://...`) | Älykäs HTTP; kloonaus ja nouto siirtyvät tarvittaessa yksinkertaiseen HTTP-protokollaan |

`git://`-URL-osoitteet ja paikalliset polut eivät ole näiden menetelmien tukemia: ne ohjataan älykkäälle HTTP-asiakkaalle ja aiheuttavat virheen. Käytä `GitProtocolClient` suoraan kohteelle `git://`. HTTPS URL, jossa on sekä käyttäjä että portti (`https://user@host:8443/repo.git`), tulkitaan tällä hetkellä virheellisesti SSH URL-osoitteeksi ([#17](https://github.com/inline0/pitmaster/issues/17)).
