Pereiti prie turinio

Git LFS

Git Large File Storage (LFS) saugykloje didelius failus pakeičia mažais rodyklių failais. Tikrasis failų turinys saugomas atskirame LFS serveryje. Pitmaster gali analizuoti ir kurti LFS rodykles bei bendrauti su LFS serveriais naudodama paketinį API. Ji neskaito .gitattributes ir nevykdo LFS clean bei smudge filtrų: add() failus saugo tokius, kokie jie yra, o checkout() įrašo rodyklių failus. Tikrojo turinio gavimas paliekamas jūsų kodui, kaip parodyta toliau.

LFS rodyklių failai

Kai failas sekamas per LFS, git vietoj tikrojo turinio saugo rodyklės failą:

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

Rodyklėje yra:

  • version: LFS specifikacijos versija URL
  • oid: tikrojo failo turinio maiša SHA-256 (prieš ją rašoma sha256:)
  • size: tikrojo failo dydis baitais

Rodyklių analizė

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() grąžina null, jei trūksta version, oid sha256: arba size eilutės. Reikšmės netikrinamos (priimamas ir ne šešioliktainis OID, ir ne skaitinis dydis).

Rodyklių aptikimas

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

isPointer() patikrina, ar yra versijos URL, oid sha256: ir size laukai, bet neatlieka išsamios analizės.

Rodyklių kūrimas

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

Rodyklių serializavimas

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

LFS klientas

LfsClient bendrauja su LFS serveriais naudodama paketinį API (POST į <url>/objects/batch).

Kliento kūrimas

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);

fromRemoteUrl() metodas atitinka standartinę konvenciją: prie git URL prideda /info/lfs (pridedama .git, jei jos nėra). Tinkamą LFS URL suteikia tik HTTP(S) nuotolinių saugyklų URL; SCP formato SSH nuotolinės saugyklos (git@host:repo.git) netinka.

LfsClient naudoja PHP srauto apvalkalą HTTP (allow_url_fopen turi būti įjungta). Jis nesiunčia prisijungimo duomenų ir nepaiso su kiekvienu veiksmu grąžinamo header susiejimo, todėl veikia tik su LFS serveriais ir saugyklos URL adresais, kuriems nereikia autentifikavimo. Jis nesusietas su saugyklos deskriptoriumi, todėl siunčia tinklo užklausas net dirbant su saugykla, atidaryta naudojant Pitmaster::processFreeOptions().

Failų atsisiuntimas

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

Viduje download():

  1. Siunčia paketinę užklausą download operacijai
  2. Iš serverio gauna atsisiuntimo URL
  3. Atsisiunčia failo turinį iš to URL

Atsisiųsti baitai netikrinami pagal OID ar dydį.

Paketinis atsisiuntimas

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']
    }
}

Failų įkėlimas

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

Įkeliant siunčiama paketinė užklausa upload operacijai. Jei serveris objektą jau turi, jis negrąžina įkėlimo URL, todėl nieko nevyksta. Pats įkėlimo užklausos rezultatas netikrinamas, taigi nepavykęs įkėlimas nepranešamas, o veiksmas verify neiškviečiamas.

Paketinis įkėlimas

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
}

Paketinio API protokolas

LFS paketinis API naudoja JSON per HTTP:

Užklausa

Kodas
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}
    ]
}

Atsakymas

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

LFS integravimas į saugyklos operacijas

Skaitant LFS naudojančią saugyklą, blob turinys gali būti LFS rodyklės, o ne tikrieji failų duomenys. Norėdami gauti tikrąjį turinį:

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;
}

Klaidų tvarkymas

Nepavykusi arba netinkama paketinė užklausa ir nepavykusi atsisiuntimo užklausa išmeta ProtocolException. download() taip pat išmeta klaidą, kai serveris objektui negrąžina atsisiuntimo URL, ir nenurodo serverio klaidos pranešimo. batchDownload() ir batchUpload() dėl atskirų objektų klaidų klaidų neišmeta – jos grąžinamos lauke 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";
}

LFS rodyklės savybės

Klasė LfsPointer yra tik skaitoma:

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