
# Αναφορές

Οι 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

Το 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');
```
