Git LFS
Το Git Large File Storage (LFS) αντικαθιστά τα μεγάλα αρχεία του αποθετηρίου σας με μικρά αρχεία δεικτών. Το πραγματικό περιεχόμενο αποθηκεύεται σε ξεχωριστό διακομιστή LFS. Το Pitmaster μπορεί να αναλύει και να δημιουργεί δείκτες LFS και να επικοινωνεί με διακομιστές LFS μέσω του batch API. Δεν διαβάζει το .gitattributes ούτε εκτελεί τα φίλτρα clean και smudge του LFS: το add() αποθηκεύει τα αρχεία όπως είναι και το checkout() γράφει αρχεία δεικτών. Η ανάκτηση του πραγματικού περιεχομένου επαφίεται στον κώδικά σας, όπως φαίνεται παρακάτω.
Αρχεία δεικτών LFS
Όταν ένα αρχείο παρακολουθείται από το LFS, το git αποθηκεύει ένα αρχείο δείκτη αντί για το πραγματικό περιεχόμενο:
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 12345
Ο δείκτης περιέχει:
version: την έκδοση προδιαγραφής LFS URLoid: το hash SHA-256 του πραγματικού περιεχομένου αρχείου (με πρόθεμαsha256:)size: το πραγματικό μέγεθος αρχείου σε byte
Ανάλυση δεικτών
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() επιστρέφει null όταν λείπει η γραμμή version, oid sha256: ή size. Δεν επικυρώνει τις τιμές (γίνεται δεκτό μη δεκαεξαδικό OID ή μη αριθμητικό μέγεθος).
Εντοπισμός δεικτών
if (LfsPointer::isPointer($blobContent)) {
// This blob is an LFS pointer, not actual file content
$pointer = LfsPointer::parse($blobContent);
}
Το isPointer() ελέγχει αν υπάρχουν τα πεδία έκδοσης URL, oid sha256: και size, χωρίς πλήρη ανάλυση.
Δημιουργία δεικτών
// 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
Σειριοποίηση δεικτών
$content = $pointer->serialize();
// "version https://git-lfs.github.com/spec/v1\noid sha256:4d7a21...\nsize 12345\n"
Πελάτης LFS
Το LfsClient επικοινωνεί με διακομιστές LFS χρησιμοποιώντας το batch API (POST στο <url>/objects/batch).
Δημιουργία πελάτη
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() ακολουθεί την καθιερωμένη σύμβαση: προσθέτει το /info/lfs στο git URL (προσθέτοντας το .git αν λείπει). Μόνο τα απομακρυσμένα URL HTTP(S) παρέχουν αξιοποιήσιμο LFS URL· τα remote σε μορφή SCP SSH (git@host:repo.git) δεν το παρέχουν.
Το LfsClient χρησιμοποιεί το περιτύλιγμα ροής HTTP του PHP (πρέπει να είναι ενεργοποιημένο το allow_url_fopen). Δεν στέλνει διαπιστευτήρια και αγνοεί τον χάρτη header που επιστρέφεται με κάθε ενέργεια, επομένως λειτουργεί μόνο με διακομιστές LFS και URL αποθήκευσης που δεν απαιτούν έλεγχο ταυτότητας. Δεν συνδέεται με χειριστή αποθετηρίου, οπότε πραγματοποιεί αιτήματα δικτύου ακόμη κι όταν εργάζεστε με αποθετήριο που άνοιξε με Pitmaster::processFreeOptions().
Λήψη αρχείων
// Single file download
$content = $client->download($pointer->oid, $pointer->size);
file_put_contents('large-file.bin', $content);
Στο παρασκήνιο, το download():
- Στέλνει αίτημα batch για τη λειτουργία
download - Λαμβάνει ένα URL λήψης από τον διακομιστή
- Ανακτά το περιεχόμενο του αρχείου από αυτό το URL
Τα byte που λαμβάνονται δεν ελέγχονται ως προς το OID ή το μέγεθος.
Λήψη σε δέσμη
$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']
}
}
Μεταφόρτωση αρχείων
$client->upload($pointer->oid, $pointer->size, $fileContent);
Η μεταφόρτωση στέλνει αίτημα batch για τη λειτουργία upload. Αν ο διακομιστής έχει ήδη το αντικείμενο, δεν επιστρέφει URL μεταφόρτωσης και η λειτουργία δεν κάνει τίποτα. Το αποτέλεσμα του ίδιου του αιτήματος μεταφόρτωσης δεν ελέγχεται, επομένως μια αποτυχημένη μεταφόρτωση δεν αναφέρεται και δεν καλείται η ενέργεια verify.
Μεταφόρτωση σε δέσμη
$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
Το batch API του LFS χρησιμοποιεί JSON μέσω HTTP:
Αίτημα
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}
]
}
Απάντηση
{
"objects": [
{
"oid": "abc123...",
"size": 12345,
"actions": {
"download": {
"href": "https://storage.example.com/abc123...",
"header": {
"Authorization": "Bearer token"
}
}
}
}
]
}
Ενσωμάτωση LFS στις λειτουργίες αποθετηρίου
Κατά την ανάγνωση αποθετηρίου που χρησιμοποιεί LFS, το περιεχόμενο των blob μπορεί να είναι δείκτες LFS αντί για πραγματικά δεδομένα αρχείων. Για να λάβετε το πραγματικό περιεχόμενο:
$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;
}
Χειρισμός σφαλμάτων
Ένα αποτυχημένο ή μη έγκυρο αίτημα batch και ένα αποτυχημένο αίτημα λήψης προκαλούν ProtocolException. Το download() προκαλεί επίσης σφάλμα όταν ο διακομιστής δεν επιστρέφει URL λήψης για το αντικείμενο, χωρίς το μήνυμα σφάλματος του διακομιστή. Τα batchDownload() και batchUpload() δεν προκαλούν σφάλμα για σφάλματα ανά αντικείμενο· τα επιστρέφουν στο πεδίο error.
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
Η κλάση LfsPointer είναι μόνο για ανάγνωση:
$pointer->oid; // string: SHA-256 hash (hex)
$pointer->size; // int: file size in bytes
$pointer->version; // string: spec version URL