Lewati ke konten

Git LFS

Git Large File Storage (LFS) mengganti file besar di repositori Anda dengan file pointer kecil. Konten file sebenarnya disimpan di server LFS terpisah. Pitmaster dapat mengurai dan membuat pointer LFS serta berkomunikasi dengan server LFS melalui API batch .gitattributes dan tidak membaca add() atau menjalankan filter clean dan smudge LFS: checkout() menyimpan file apa adanya, dan menulis file pointer. Pengambilan konten sebenarnya menjadi tanggung jawab kode Anda, seperti yang ditunjukkan di bawah.

File Pointer LFS

Saat file dilacak oleh LFS, git menyimpan file pointer sebagai pengganti konten sebenarnya:

Kode
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 12345

Pointer berisi:

  • version: versi spesifikasi LFS URL
  • oid: hash SHA-256 dari konten file sebenarnya (diawali dengan sha256:)
  • size: ukuran file sebenarnya dalam byte

Mengurai pointer

PHP
use Pitmaster\Lfs\LfsPointer;

$content = file_get_contents('.git-lfs-tracked-file');
$pointer = LfsPointer::parse($content);

if ($pointer !== null) {
    echo "OID: {$pointer->oid}\n";
    echo "Size: {$pointer->size}\n";
    echo "Version: {$pointer->version}\n";
}

parse() mengembalikan null jika baris version, oid sha256:, atau size tidak ada. Nilainya tidak divalidasi (OID non-heksadesimal atau ukuran nonnumerik tetap diterima).

Mendeteksi pointer

PHP
if (LfsPointer::isPointer($blobContent)) {
    // This blob is an LFS pointer, not actual file content
    $pointer = LfsPointer::parse($blobContent);
}

isPointer() memeriksa keberadaan field version URL, oid sha256:, dan size tanpa parsing lengkap.

Membuat pointer

PHP
// From known OID and size
$pointer = new LfsPointer(
    oid: '4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393',
    size: 12345,
);

// From file content (computes SHA-256 hash)
$pointer = LfsPointer::forContent($actualFileContent);

echo $pointer->oid;   // SHA-256 hash
echo $pointer->size;  // Content length

Membuat serialisasi pointer

PHP
$content = $pointer->serialize();
// "version https://git-lfs.github.com/spec/v1\noid sha256:4d7a21...\nsize 12345\n"

Klien LFS

LfsClient berkomunikasi dengan server LFS menggunakan API batch (POST ke <url>/objects/batch).

Membuat klien

PHP
use Pitmaster\Lfs\LfsClient;

// From a git remote URL (appends /info/lfs)
$client = LfsClient::fromRemoteUrl('https://github.com/user/repo.git');
// LFS URL: https://github.com/user/repo.git/info/lfs

// Direct URL
$client = new LfsClient('https://lfs.example.com/repo', timeout: 60);

Metode fromRemoteUrl() mengikuti konvensi standar: menambahkan /info/lfs ke URL git (menambahkan .git jika belum ada). Hanya URL remote HTTP(S) yang menghasilkan URL LFS yang dapat digunakan; remote SSH bergaya SCP (git@host:repo.git) tidak bisa digunakan.

LfsClient menggunakan wrapper stream HTTP milik PHP (allow_url_fopen harus diaktifkan). Wrapper ini tidak mengirim kredensial dan mengabaikan peta header yang dikembalikan bersama setiap tindakan, sehingga hanya berfungsi dengan server LFS dan URL penyimpanan yang tidak memerlukan autentikasi. Wrapper ini tidak terikat pada handle repositori, sehingga tetap membuat permintaan jaringan saat Anda bekerja dengan repositori yang dibuka menggunakan Pitmaster::processFreeOptions().

Mengunduh file

PHP
// Single file download
$content = $client->download($pointer->oid, $pointer->size);
file_put_contents('large-file.bin', $content);

Di balik layar, download():

  1. Mengirim permintaan batch untuk operasi download
  2. Menerima URL unduhan dari server
  3. Mengambil konten file dari URL tersebut

Byte yang diunduh tidak diperiksa terhadap OID atau ukuran.

Unduhan batch

PHP
$results = $client->batchDownload([
    ['oid' => 'abc123...', 'size' => 12345],
    ['oid' => 'def456...', 'size' => 67890],
]);

foreach ($results as $result) {
    if ($result['error'] !== null) {
        echo "Error: {$result['error']}\n";
        continue;
    }

    if ($result['href'] !== null) {
        // Download from $result['href']
    }
}

Mengunggah file

PHP
$client->upload($pointer->oid, $pointer->size, $fileContent);

Pengunggahan mengirim permintaan batch untuk operasi upload. Jika server sudah memiliki objek tersebut, server tidak mengembalikan URL unggahan sehingga operasi tidak melakukan apa pun. Hasil permintaan unggah itu sendiri tidak diperiksa, jadi kegagalan unggah tidak dilaporkan dan tindakan verify tidak dipanggil.

Unggahan batch

PHP
$results = $client->batchUpload([
    ['oid' => 'abc123...', 'size' => 12345],
]);

foreach ($results as $result) {
    if ($result['href'] !== null) {
        // Server needs this object, upload to $result['href']
    }
    // No href means server already has it
}

Protokol API batch

Batch LFS API menggunakan JSON melalui HTTP:

Permintaan

Kode
POST <lfs-url>/objects/batch
Content-Type: application/vnd.git-lfs+json
Accept: application/vnd.git-lfs+json

{
    "operation": "download",
    "transfers": ["basic"],
    "objects": [
        {"oid": "abc123...", "size": 12345}
    ]
}

Respons

JSON
{
    "objects": [
        {
            "oid": "abc123...",
            "size": 12345,
            "actions": {
                "download": {
                    "href": "https://storage.example.com/abc123...",
                    "header": {
                        "Authorization": "Bearer token"
                    }
                }
            }
        }
    ]
}

Mengintegrasikan LFS dengan operasi repositori

Saat membaca repositori yang menggunakan LFS, konten blob mungkin berupa pointer LFS, bukan data file sebenarnya. Untuk mendapatkan konten sebenarnya:

PHP
$blob = $repo->readObject($hash);

if (LfsPointer::isPointer($blob->content)) {
    $pointer = LfsPointer::parse($blob->content);
    $remoteUrl = $repo->config()->get('remote.origin.url');
    $client = LfsClient::fromRemoteUrl($remoteUrl);
    $realContent = $client->download($pointer->oid, $pointer->size);
} else {
    $realContent = $blob->content;
}

Penanganan error

Permintaan batch yang gagal atau tidak valid, serta permintaan unduhan yang gagal, melempar ProtocolException. download() juga melempar error jika server tidak mengembalikan URL unduhan untuk objek tersebut, tanpa pesan error dari server. batchDownload() dan batchUpload() tidak melempar error untuk kesalahan per objek; keduanya mengembalikan kesalahan tersebut di field error.

PHP
use Pitmaster\Exceptions\ProtocolException;

try {
    $content = $client->download($oid, $size);
} catch (ProtocolException $e) {
    // Server unreachable, invalid response, no download URL
    echo "LFS error: {$e->getMessage()}\n";
}

Properti pointer LFS

Class LfsPointer hanya dapat dibaca:

PHP
$pointer->oid;      // string: SHA-256 hash (hex)
$pointer->size;     // int: file size in bytes
$pointer->version;  // string: spec version URL