Siirry sisältöön

Git LFS

Git Large File Storage (LFS) korvaa arkiston suuret tiedostot pienillä osoitintiedostoilla. Varsinainen tiedostosisältö tallennetaan erilliselle LFS-palvelimelle. Pitmaster voi jäsentää ja luoda LFS-osoittimia sekä viestiä LFS-palvelimien kanssa batch-API-rajapinnan kautta. Se ei lue .gitattributes-tiedostoja eikä suorita LFS clean- ja smudge-suodattimia: add() tallentaa tiedostot sellaisinaan, ja checkout() kirjoittaa osoitintiedostot. Koodisi vastuulla on hakea varsinainen sisältö, kuten alla näytetään.

LFS-osoitintiedostot

Kun tiedostoa seurataan LFS:llä, git tallentaa varsinaisen sisällön sijaan osoitintiedoston:

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

Osoitin sisältää:

  • version: LFS-määrityksen versio URL
  • oid: varsinaisen tiedostosisällön SHA-256-tiiviste (etuliitteenä sha256:)
  • size: varsinaisen tiedoston koko tavuina

Osoittimien jäsentäminen

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() palauttaa arvon null, jos rivi version, oid sha256: tai size puuttuu. Se ei validoi arvoja (ei-heksadesimaalinen OID tai ei-numeerinen koko hyväksytään).

Osoittimien tunnistaminen

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

isPointer() tarkistaa, ovatko version URL, oid sha256: ja size-kentät olemassa, mutta ei jäsennä niitä kokonaan.

Osoittimien luominen

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

Osoittimien sarjallistaminen

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

LFS-asiakas

LfsClient viestii LFS-palvelimien kanssa batch-API-rajapinnalla (POST osoitteeseen <url>/objects/batch).

Asiakkaan luominen

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()-metodi noudattaa vakiokäytäntöä: se lisää /info/lfs-päätteen git-URL-osoitteeseen (lisää .git, jos sitä ei ole). Vain HTTP(S)-muotoiset etäosoitteet antavat käyttökelpoisen LFS-URL-osoitteen; SCP-tyyliset SSH-etäosoitteet (git@host:repo.git) eivät.

LfsClient käyttää PHP-virran kääretoimintoa HTTP (allow_url_fopen on oltava käytössä). Se ei lähetä tunnistetietoja eikä huomioi kunkin toiminnon mukana palautettavaa header-karttaa, joten se toimii vain LFS-palvelimien ja tallennusosoitteiden kanssa, jotka eivät vaadi todennusta. Se ei ole sidottu arkistokahvaan, joten se tekee verkkopyyntöjä myös silloin, kun työskentelet arkistossa, joka on avattu kahvalla Pitmaster::processFreeOptions().

Tiedostojen lataaminen

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

Taustalla download():

  1. Lähettää batch-pyynnön download-toiminnosta
  2. Saa palvelimelta lataus-URL-osoitteen
  3. Hakee tiedoston sisällön kyseisestä URL-osoitteesta

Ladattuja tavuja ei tarkisteta OID:n tai koon perusteella.

Lataaminen batch-pyynnöllä

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

Tiedostojen lähettäminen

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

Lähetys lähettää batch-pyynnön upload-toiminnosta. Jos palvelimella on jo objekti, se ei palauta lähetys-URL-osoitetta eikä mitään tapahdu. Lähetyspyynnön tulosta ei tarkisteta, joten epäonnistuneesta lähetyksestä ei ilmoiteta eikä verify-toimintoa kutsuta.

Lähettäminen batch-pyynnöllä

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-protokolla

LFS:n batch-API käyttää JSON-menetelmää osoitteessa HTTP:

Pyyntö

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

Vastaus

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

LFS:n integrointi arkistotoimintoihin

LFS:ää käyttävässä arkistossa blob-sisältö voi olla LFS-osoittimia varsinaisen tiedostodatan sijaan. Saat varsinaisen sisällön näin:

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

Virheenkäsittely

Epäonnistunut tai virheellinen batch-pyyntö ja epäonnistunut latauspyyntö aiheuttavat ProtocolException-poikkeuksen. download() aiheuttaa poikkeuksen myös silloin, kun palvelin ei palauta objektille lataus-URL-osoitetta, mutta ei sisällytä palvelimen virheilmoitusta. batchDownload() ja batchUpload() eivät aiheuta poikkeusta objektikohtaisista virheistä, vaan palauttavat ne error-kentässä.

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-osoittimen ominaisuudet

LfsPointer-luokka on vain luettavissa:

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