Μετάβαση στο περιεχόμενο

Αναφορές

Οι refs (αναφορές) είναι επώνυμοι δείκτες σε commit. Οι κλάδοι, τα tags, το HEAD και οι refs παρακολούθησης απομακρυσμένων είναι όλα refs. Το Pitmaster διαβάζει refs από loose αρχεία, packed-refs και reftable, και γράφει loose αρχεία και packed-refs.

RefDatabase

Το RefDatabase είναι το σύνθετο επίπεδο που αναζητά πρώτα loose refs, έπειτα reftable (όταν το αποθετήριο διαθέτει ένα) και μετά packed-refs.

PHP
use Pitmaster\Ref\RefDatabase;

$refs = new RefDatabase($gitDir, $commonDir);

// Resolve a ref to an ObjectId
$id = $refs->resolve('refs/heads/main');

// Resolve HEAD (follows symbolic refs)
$headId = $refs->resolveHead();

// Read HEAD as a symbolic ref (null when HEAD is detached)
$symref = $refs->readHead();
echo $symref?->target;  // 'refs/heads/main'

// List all refs
foreach ($refs->list() as $name => $id) {
    echo "{$id->hex} {$name}\n";
}

// Update a ref
$refs->update('refs/heads/main', $newCommitId);

// Delete a ref
$refs->delete('refs/heads/old-branch');

Για συνδεδεμένα worktrees, το RefDatabase διατηρεί το HEAD και τις άλλες ψευδο-refs ανά worktree (ORIG_HEAD, MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD, REBASE_HEAD, BISECT_HEAD) στον κατάλογο git του συγκεκριμένου worktree. Οι κλάδοι, τα tags και οι άλλες εγγραφές refs/ γράφονται στον κοινό κατάλογο, ενώ το packed-refs διαβάζεται πάντα από τον κοινό κατάλογο.

Χαλαρές αναφορές

Οι loose refs είναι μεμονωμένα αρχεία στο .git/refs/. Κάθε αρχείο περιέχει το δεκαεξαδικό hash του αντικειμένου-στόχου (40 χαρακτήρες ή 64 για SHA-256), ακολουθούμενο από αλλαγή γραμμής.

Κώδικας
.git/refs/heads/main           -> abc123def456...\n
.git/refs/tags/v1.0.0          -> 789012abc345...\n
.git/refs/remotes/origin/main  -> abc123def456...\n
PHP
use Pitmaster\Ref\LooseRefStore;

$store = new LooseRefStore($gitDir, $commonDir); // $commonDir defaults to $gitDir

$id = $store->resolve('refs/heads/main');
$store->update('refs/heads/main', $commitId);
$store->delete('refs/heads/old');

Το HEAD είναι μια ειδική ref που μπορεί να είναι είτε:

Συμβολική: δείχνει σε άλλη ref (το συνηθέστερο όταν βρίσκεστε σε κλάδο):

Κώδικας
ref: refs/heads/main\n

Αποσυνδεδεμένη: δείχνει απευθείας σε hash commit:

Κώδικας
abc123def456789012abc345def678901234abcd\n
PHP
use Pitmaster\Ref\SymbolicRef;

$symref = SymbolicRef::parse('HEAD', $headContent);

if ($symref !== null) {
    echo "On branch: {$symref->target}\n";
    // 'refs/heads/main'
} else {
    echo "Detached HEAD\n";
}

Συμπιεσμένες αναφορές

Το αρχείο packed-refs συνδυάζει πολλές refs σε ένα αρχείο για μεγαλύτερη αποδοτικότητα. Το Git το δημιουργεί κατά τη διάρκεια git pack-refs ή git gc.

Κώδικας
# pack-refs with: peeled fully-peeled sorted
abc123def456789012abc345def678901234abcd refs/heads/main
789012abc345def678901234abcdabc123def456 refs/tags/v1.0.0
^def456789012abc345def678901234abcdabc12

Οι γραμμές που αρχίζουν με ^ είναι τιμές peeled: το commit στο οποίο δείχνει τελικά ένα σχολιασμένο tag.

PHP
use Pitmaster\Ref\PackedRefStore;

$store = new PackedRefStore($commonDir);

$id = $store->resolve('refs/heads/main');

foreach ($store->list() as $name => $id) {
    echo "{$id->hex} {$name}\n";
}

Τιμές peeled

Για σχολιασμένα tags, το αρχείο packed-refs μπορεί να περιλαμβάνει την τιμή peeled (χωρίς αναφορά) στη γραμμή μετά την ref του tag. Η τιμή peeled είναι το commit στο οποίο δείχνει τελικά το αντικείμενο tag (ενδεχομένως μέσω πολλών αντικειμένων tag).

PHP
$peeled = $store->peeled('refs/tags/v1.0.0');
// Returns the commit ObjectId, or null if not peeled

Σειρά επίλυσης ref

Κατά την επίλυση μιας ref, το Pitmaster ελέγχει με την εξής σειρά:

  1. Loose ref (αρχείο στο .git/refs/)
  2. Reftable, όταν υπάρχει το .git/reftable/tables.list
  3. Packed ref (εγγραφή στο .git/packed-refs)

Οι loose refs έχουν προτεραιότητα. Όταν ενημερώνεται μια packed ref, η νέα τιμή γράφεται ως loose ref (το αρχείο packed-refs δεν ξαναγράφεται). Η διαγραφή μιας ref αφαιρεί τόσο το loose αρχείο όσο και την εγγραφή packed. Το $repo->packRefs() ξαναγράφει το packed-refs από τις τρέχουσες refs και αφαιρεί τα loose αρχεία.

SymbolicRef

Οι συμβολικές refs είναι αναφορές που δείχνουν σε άλλες αναφορές αντί απευθείας σε αντικείμενα.

PHP
use Pitmaster\Ref\SymbolicRef;

// Parse
$ref = SymbolicRef::parse('HEAD', "ref: refs/heads/main\n");
echo $ref->name;    // 'HEAD'
echo $ref->target;  // 'refs/heads/main'

// Update
$refs->updateSymbolic('HEAD', 'refs/heads/feature');

Reflog

Το reflog καταγράφει πότε αλλάζουν οι refs, επιτρέποντας στο git reflog να εμφανίζει το ιστορικό του HEAD και των άκρων των κλάδων.

Τα αρχεία Reflog βρίσκονται στο .git/logs/:

Κώδικας
.git/logs/HEAD
.git/logs/refs/heads/main
.git/logs/refs/stash

Κάθε γραμμή καταγράφει:

Κώδικας
<old-hash> <new-hash> <author> <timestamp> <tz>\t<message>
PHP
use Pitmaster\Ref\Reflog;

$reflog = Reflog::open($gitDir, 'HEAD');

// Read entries
$entries = $reflog->entries();
foreach ($entries as $entry) {
    echo "{$entry['old']} -> {$entry['new']}: {$entry['message']}\n";
}

// Append an entry
$reflog->append(
    $oldId,
    $newId,
    'Name <email> 1700000000 +0000',
    'commit: Add feature',
);

Το stash χρησιμοποιεί το reflog του refs/stash ως αποθήκευση στοίβας.

Reftable

Το Reftable είναι μια νεότερη δυαδική μορφή για την αποθήκευση refs, σχεδιασμένη για καλύτερη απόδοση με πολλές refs (χιλιάδες κλάδους). Αντικαθιστά τόσο τις loose refs όσο και το packed-refs.

Τα αρχεία Reftable αποθηκεύονται στο .git/reftable/ και περιέχουν:

  • Εγγραφές ref (ταξινομημένες κατά όνομα)
  • Εγγραφές log (καταχωρίσεις reflog)
  • Ευρετηρίαση σε επίπεδο μπλοκ για γρήγορες αναζητήσεις

Το Pitmaster διαβάζει τις εγγραφές ref των αρχείων reftable όταν υπάρχουν· οι εγγραφές log δεν διαβάζονται. Όταν υπάρχει reftable, αντικαθιστά το packed-refs για την εμφάνιση καταχωρίσεων. Οι ενημερώσεις ref γράφονται πάντα ως loose αρχεία, τα οποία το git δεν διαβάζει σε αποθετήριο reftable, επομένως θεωρήστε τα αποθετήρια reftable μόνο για ανάγνωση.

Συμβάσεις ονομασίας ref

Μοτίβο Σημασία
refs/heads/<name> Τοπικός κλάδος
refs/tags/<name> Tag (ελαφρύ ή σχολιασμένο)
refs/remotes/<remote>/<name> Κλάδος παρακολούθησης απομακρυσμένου
refs/stash Στοίβα stash
refs/notes/<namespace> Σημειώσεις Git
HEAD Τρέχον checkout (συμβολικό ή αποσυνδεδεμένο)
FETCH_HEAD Αποτέλεσμα τελευταίου fetch (γράφεται από το git· το Pitmaster του fetch() δεν το γράφει)
MERGE_HEAD Κλάδος που συγχωνεύεται (κατά τη συγχώνευση)
ORIG_HEAD Προηγούμενο HEAD (πριν από επικίνδυνες λειτουργίες)

Εργασία με refs μέσω του Repository

PHP
// Read
$branch = $repo->branch();          // Current branch name
$branches = $repo->branches();      // All branch names
$tags = $repo->tags();              // All tag names
$refs = $repo->allRefs();           // All refs as name => hash

// Write
$repo->createBranch('feature');     // Create refs/heads/feature
$repo->deleteBranch('feature');     // Delete refs/heads/feature
$repo->createTag('v1.0', 'Release');// Create annotated tag
$repo->createLightweightTag('v1.0-lite'); // Create lightweight tag
$repo->updateRef('refs/heads/main', $id); // Direct ref update

// Resolve
$id = $repo->resolve('HEAD');
$id = $repo->resolve('main');
$id = $repo->resolve('v1.0.0');
$id = $repo->resolve('HEAD~3');