Smart HTTP
Pitmaster berkomunikasi dengan server git melalui HTTPS menggunakan protokol smart HTTP. Ini adalah transport jaringan utama. Protokol ini menggunakan fungsi stream native milik PHP (fopen dengan konteks stream) untuk permintaan HTTP, jadi allow_url_fopen harus diaktifkan.
SmartHttpClient
use Pitmaster\Protocol\SmartHttpClient;
$http = new SmartHttpClient();
// Or with custom timeout:
$http = new SmartHttpClient(timeout: 60);
Batas waktu default-nya adalah konstanta PITMASTER_HTTP_TIMEOUT (bilangan bulat), atau 30 detik jika konstanta tersebut tidak ditentukan.
Temukan ref
$discovery = $http->discoverRefs('https://github.com/user/repo.git');
foreach ($discovery->refs() as $name => $id) {
echo "{$id->hex} {$name}\n";
}
// HEAD symref (e.g., 'refs/heads/main')
$defaultBranch = $discovery->headSymref();
// Specific ref
$mainId = $discovery->ref('refs/heads/main');
// Server capabilities (a Capability object, or null)
$caps = $discovery->capabilities();
discoverReceivePackRefs() melakukan hal yang sama untuk git-receive-pack. Permintaan discovery ref dikirim ke:
GET <url>/info/refs?service=git-upload-pack
Responsnya berupa daftar ref berkode pkt-line dengan kapabilitas pada baris pertama.
Upload pack (fetch)
$response = $http->uploadPack($url, $requestBody);
Mengirim POST ke <url>/git-upload-pack dengan isi permintaan negosiasi want/have. Mengembalikan isi respons mentah (pkt-lines, NAK, dan data side-band). UploadPackClient menyusun permintaan dan mengekstrak pack:
use Pitmaster\Protocol\UploadPackClient;
$client = new UploadPackClient($http);
$packData = $client->fetch($url, $wants, $haves); // ObjectId[] wants and haves
Receive pack (push)
$response = $http->receivePack($url, $requestBody);
Mengirim POST ke <url>/git-receive-pack dengan perintah pembaruan ref dan data pack.
Encoding PktLine
Protokol git menggunakan framing pkt-line untuk semua komunikasi. Setiap baris diawali panjang totalnya (termasuk prefiks panjang 4 byte) yang dikodekan sebagai 4 digit heksadesimal.
use Pitmaster\Protocol\PktLine;
// Encode a single line
$encoded = PktLine::encode("want abc123def456\n");
// "0016want abc123def456\n"
// Flush packet (end of section)
$flush = PktLine::flush();
// "0000"
// Delimiter packet (protocol v2)
$delim = PktLine::delimiter();
// "0001"
// Decode a stream
$lines = PktLine::decode($rawData);
// Each element is: string (data), null (flush), or false (delimiter)
Aturan panjang
- Baris data minimum:
0005(payload 1 byte) - Baris data maksimum:
fff0(payload 65516 byte) - Paket flush:
0000 - Paket delimiter:
0001 - Akhir respons:
0002(protokol v2; ditangani olehProtocolV2::decode(), sedangkanPktLine::decode()menolaknya)
PktLine::MAX_PAYLOAD; // 65516 (65520 - 4)
Discovery ref
Kelas RefDiscovery mengurai iklan ref dari server.
use Pitmaster\Protocol\RefDiscovery;
$discovery = RefDiscovery::parse($pktLines);
// All refs
$refs = $discovery->refs();
// ['refs/heads/main' => ObjectId, 'refs/tags/v1.0' => ObjectId, ...]
// Single ref
$id = $discovery->ref('refs/heads/main');
// HEAD symbolic ref (from capabilities)
$symref = $discovery->headSymref();
// 'refs/heads/main' or null
// Server capabilities
$caps = $discovery->capabilities();
// Capability object (see below), or null
Format iklan ref
Baris pertama iklan tersebut mencakup kapabilitas:
<hash> HEAD\0<capability list>\n
<hash> refs/heads/main\n
<hash> refs/tags/v1.0\n
0000
Kapabilitas
Kelas Capability mengurai dan mengelola kapabilitas protokol.
use Pitmaster\Protocol\Capability;
$caps = Capability::parse('thin-pack side-band-64k ofs-delta symref=HEAD:refs/heads/main');
$caps->has('thin-pack'); // true
$caps->get('symref'); // 'HEAD:refs/heads/main'
$caps->all(); // ['thin-pack' => null, ..., 'symref' => 'HEAD:refs/heads/main']
Kapabilitas umum
| Kapabilitas | Arti |
|---|---|
multi_ack |
Server mendukung negosiasi multi-ack |
thin-pack |
Server mengirim pack tipis (objek dasar dapat dihilangkan). Pitmaster memintanya, tetapi belum dapat mengindeks pack tipis (#16) |
side-band |
Server menggunakan side-band untuk data pack (terbatas hingga 1000 byte) |
side-band-64k |
Server menggunakan side-band 64K untuk data pack |
ofs-delta |
Pack dapat menggunakan objek OFS_DELTA |
shallow |
Server mendukung clone dangkal |
no-done |
Server tidak memerlukan baris "done" |
symref=HEAD:refs/heads/main |
Target simbolis HEAD |
agent=git/2.45.0 |
Versi git server |
Demultipleks side-band
Saat server menggunakan side-band, data pack dimultipleks bersama pesan progres dan kesalahan. Byte pertama dari setiap payload pkt-line menunjukkan kanalnya:
| Kanal | Arti |
|---|---|
| 1 | Data pack |
| 2 | Pesan progres (stderr) |
| 3 | Pesan kesalahan fatal |
Pitmaster milik UploadPackClient menghapus byte kanal dan menyusun kembali data pack.
Versi protokol
v1 (default)
Protokol tradisional. Discovery ref mengirim semua ref sekaligus. Pitmaster bernegosiasi dalam satu putaran: mengirim wants-nya, setiap tip ref lokal sebagai have, dan done.
v2
Protokol yang lebih sederhana dengan performa lebih baik.
Perbedaan utama dari v1:
- Discovery ref adalah perintah
ls-refsterpisah (dapat memfilter ref) - Fetch adalah satu perintah
fetchdengan parameter terstruktur - Menggunakan paket delimiter (
0001) untuk memisahkan bagian
clone() dan fetch() selalu menggunakan v1. v2 tersedia jika Anda memanggilnya secara eksplisit:
$discovery = $http->discoverRefsV2($url); // ls-refs
$packData = (new UploadPackClient($http))->fetchV2($url, $wants, $haves);
Alur permintaan HTTP
Clone/Fetch
1. GET /info/refs?service=git-upload-pack
Response: pkt-line encoded ref list
2. POST /git-upload-pack
Request: want <hash>\n ... have <hash>\n ... done\n
Response: NAK\n + pack data (possibly side-band wrapped)
Push
1. GET /info/refs?service=git-receive-pack
Response: pkt-line encoded ref list
2. POST /git-receive-pack
Request: <old-hash> <new-hash> refs/heads/main\0<capabilities>\n
0000
PACK<pack data>
Response: unpack ok\n + ref status lines
Penanganan error
Kesalahan jaringan melempar ProtocolException. Jika pertukaran smart HTTP untuk clone() atau fetch() gagal, Pitmaster mencoba lagi melalui dumb HTTP dan melempar ulang kesalahan awal jika upaya itu juga gagal. Kegagalan lain (remote tidak dikenal, handle tanpa proses, pack yang tidak dapat diindeks) melempar jenis pengecualian lain:
use Pitmaster\Exceptions\ProtocolException;
try {
$repo->fetch();
} catch (ProtocolException $e) {
echo "Network error: {$e->getMessage()}\n";
}
Kesalahan umum:
- Server tidak dapat dijangkau (batas waktu)
- Autentikasi diperlukan atau repositori tidak ditemukan (dilaporkan sebagai
Unexpected HTTP status 401,403, atau404) Content-Typetak terduga dalam respons- Data pkt-line tidak valid
- Pesan kanal kesalahan side-band