Ga naar de inhoud

Git LFS

Git Large File Storage (LFS) vervangt grote bestanden in uw repository door kleine pointerbestanden. De daadwerkelijke bestandsinhoud wordt op een aparte LFS-server opgeslagen. Pitmaster kan LFS-pointers parsen en aanmaken, en via de batch-API met LFS-servers communiceren. Het leest .gitattributes niet en voert de LFS clean- en smudge-filters niet uit: add() slaat bestanden ongewijzigd op en checkout() schrijft pointerbestanden. Uw code moet zelf de echte inhoud ophalen, zoals hieronder wordt getoond.

LFS-pointerbestanden

Wanneer een bestand door LFS wordt bijgehouden, slaat git een pointerbestand op in plaats van de daadwerkelijke inhoud:

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

De pointer bevat:

  • version: de LFS-specificatieversie URL
  • oid: hash van de daadwerkelijke bestandsinhoud volgens SHA-256 (met prefix sha256:)
  • size: de daadwerkelijke bestandsgrootte in bytes

Pointers parsen

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() retourneert null wanneer de regel version, oid sha256: of size ontbreekt. De waarden worden niet gevalideerd (een niet-hexadecimale OID of niet-numerieke grootte wordt geaccepteerd).

Pointers detecteren

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

isPointer() controleert of de velden version URL, oid sha256: en size aanwezig zijn, zonder de pointer volledig te parsen.

Pointers aanmaken

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

Pointers serialiseren

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

LFS-client

De LfsClient communiceert met LFS-servers via de batch-API (POST naar <url>/objects/batch).

Een client aanmaken

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

De methode fromRemoteUrl() volgt de standaardconventie: voeg /info/lfs toe aan de git-URL (en voeg .git toe als dit ontbreekt). Alleen HTTP(S)-remote-URL's leveren een bruikbare LFS-URL op; SCP-achtige SSH-remotes (git@host:repo.git) niet.

LfsClient gebruikt de HTTP-streamwrapper van PHP (allow_url_fopen moet zijn ingeschakeld). Het verzendt geen referenties en negeert de header-map die bij elke actie wordt teruggestuurd; het werkt dus alleen met LFS-servers en opslag-URL's waarvoor geen authenticatie nodig is. Het is niet gekoppeld aan een repositoryhandle en doet daarom netwerkverzoeken, ook wanneer u werkt met een repository die is geopend met Pitmaster::processFreeOptions().

Bestanden downloaden

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

Onder water doet download() het volgende:

  1. Verstuurt een batchverzoek voor de bewerking download
  2. Ontvangt een download-URL van de server
  3. Haalt de bestandsinhoud op via die URL

De gedownloade bytes worden niet gecontroleerd aan de hand van de OID of grootte.

Batchdownload

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

Bestanden uploaden

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

Bij het uploaden wordt een batchverzoek voor de bewerking upload verstuurd. Als de server het object al heeft, retourneert deze geen upload-URL en wordt er niets gedaan. Het resultaat van het uploadverzoek zelf wordt niet gecontroleerd, waardoor een mislukte upload niet wordt gemeld en de actie verify niet wordt aangeroepen.

Batchupload

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
}

Batch-API-protocol

De LFS-batch-API maakt gebruik van JSON via HTTP:

Verzoek

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

Antwoord

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

LFS integreren met repositorybewerkingen

Bij het lezen van een repository die LFS gebruikt, kan de blobinhoud uit LFS-pointers bestaan in plaats van de daadwerkelijke bestandsgegevens. Zo haalt u de echte inhoud op:

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

Foutafhandeling

Een mislukt of ongeldig batchverzoek en een mislukt downloadverzoek veroorzaken ProtocolException. download() veroorzaakt dit ook als de server geen download-URL voor het object retourneert, zonder het foutbericht van de server. batchDownload() en batchUpload() veroorzaken geen fout bij fouten voor afzonderlijke objecten; ze retourneren deze in het veld 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-pointereigenschappen

De class LfsPointer is alleen-lezen:

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