
# Αντικείμενα Git

Όλα τα στοιχεία σε ένα αποθετήριο git αποθηκεύονται ως αντικείμενα. Υπάρχουν τέσσερις τύποι: blobs (περιεχόμενο αρχείων), trees (καταχωρίσεις καταλόγων), commits (στιγμιότυπα με μεταδεδομένα) και tags (σχολιασμένες αναφορές). Κάθε αντικείμενο ταυτοποιείται από το SHA-1 του περιεχομένου του.

## Τύποι αντικειμένων

### Blob

Ένα blob περιέχει ακατέργαστο περιεχόμενο αρχείου χωρίς μεταδεδομένα (όνομα αρχείου ή δικαιώματα).

```php
use Pitmaster\Object\Blob;

// Create from content
$blob = Blob::fromContent('Hello, world!');
echo $blob->content;    // 'Hello, world!'
echo $blob->size();     // 13
echo $blob->id->hex;    // SHA-1 hash
echo $blob->type->value; // 'blob' (the property is ObjectType::Blob)
```

### Δέντρο

Ένα tree είναι μια καταχώριση καταλόγου. Κάθε εγγραφή έχει μια λειτουργία, ένα όνομα και ένα hash που δείχνει σε blob ή υποδέντρο.

```php
use Pitmaster\Object\Tree;
use Pitmaster\Object\TreeEntry;

// Read a tree
$tree = $repo->readObject($treeHash);

foreach ($tree->entries as $entry) {
    echo "{$entry->mode} {$entry->name} {$entry->hash->hex}\n";
}

// Look up a specific entry
$entry = $tree->entry('README.md');

// Create a tree (entries already in git's sort order)
$entries = [
    new TreeEntry('100644', 'README.md', $blobId),
    new TreeEntry('100755', 'deploy.sh', $execBlobId),
    new TreeEntry('40000', 'src', $subtreeId),
];

$tree = Tree::fromEntries($entries);
```

`Tree::fromEntries()` γράφει τις εγγραφές με τη σειρά που δίνονται και τις συμβολοσειρές λειτουργίας ακριβώς όπως δίνονται, επομένως ταξινομήστε τις πρώτα και γράψτε τις λειτουργίες καταλόγων ως `40000`. Ένα tree που γράφεται με `040000` ή με άλλη σειρά έχει διαφορετικό hash από εκείνο του git, ενώ το `git fsck --strict` αναφέρει τη λειτουργία με μηδενικά στην αρχή.

#### TreeEntry

Το `TreeEntry` είναι ένα αντικείμενο τιμής μόνο για ανάγνωση:

```php
use Pitmaster\Object\TreeEntry;

$entry->mode;   // '100644', '100755', '40000', '120000', '160000'
$entry->name;   // Filename
$entry->hash;   // ObjectId

// Type checks
$entry->isBlob();        // regular or executable file (mode 10xxxx)
$entry->isExecutable();  // mode 100755
$entry->isTree();        // mode 40000 (also accepts 040000)
$entry->isSymlink();     // mode 120000
$entry->isGitlink();     // mode 160000 (submodule)
```

Τιμές λειτουργίας:
| Λειτουργία | Σημασία |
|------|---------|
| `100644` | Κανονικό αρχείο |
| `100755` | Εκτελέσιμο αρχείο |
| `40000` | Κατάλογος (tree), εμφανίζεται ως `040000` από το `git ls-tree` |
| `120000` | Συμβολικός σύνδεσμος |
| `160000` | Gitlink (υπομονάδα) |

Οι εγγραφές tree ταξινομούνται κατά όνομα, με τα ονόματα καταλόγων να θεωρείται ότι τελειώνουν σε `/` για τους σκοπούς της σύγκρισης.

### Υποβολή

Ένα commit συνδέει ένα tree με το ιστορικό και τα μεταδεδομένα του.

```php
use Pitmaster\Object\Commit;

$commit = $repo->head();

$commit->id;         // ObjectId
$commit->tree;       // ObjectId of the tree
$commit->parents;    // array of ObjectId (zero for root, one for normal, two+ for merge)
$commit->author;     // 'Name <email> timestamp timezone'
$commit->committer;  // 'Name <email> timestamp timezone'
$commit->message;    // Full commit message

$commit->isMerge();  // true if two or more parents
```

#### Δημιουργία περιεχομένου commit

```php
$content = Commit::buildContent(
    tree: $treeId,
    parents: [$parentId],
    author: 'Jane <jane@example.com> 1700000000 +0000',
    committer: 'Jane <jane@example.com> 1700000000 +0000',
    message: "Add feature\n",
);
```

Η ακατέργαστη μορφή commit:

```
tree <hex hash>\n
parent <hex hash>\n       (zero or more)
author <name> <<email>> <timestamp> <tz>\n
committer <name> <<email>> <timestamp> <tz>\n
\n
<message>
```

### Ετικέτα

Τα σχολιασμένα tags είναι αντικείμενα με μεταδεδομένα.

```php
use Pitmaster\Object\Tag;

$tag = $repo->readObject($tagHash);

$tag->object;        // ObjectId of the target
$tag->objectType;    // ObjectType enum (ObjectType::Commit, ...)
$tag->name;          // Tag name
$tag->tagger;        // 'Name <email> timestamp timezone'
$tag->message;       // Tag message
```

Ακατέργαστη μορφή tag:

```
object <hex hash>\n
type commit\n
tag <name>\n
tagger <name> <<email>> <timestamp> <tz>\n
\n
<message>
```

## ObjectId

Το `ObjectId` είναι ένα αντικείμενο τιμής μόνο για ανάγνωση που αναπαριστά ένα hash SHA-1 (ή SHA-256).

```php
use Pitmaster\Object\ObjectId;
use Pitmaster\Object\ObjectType;

// From hex string
$id = ObjectId::fromHex('a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2');

// From binary (20 bytes for SHA-1, 32 for SHA-256)
$id = ObjectId::fromBinary($rawBytes);

// Compute from content
$id = ObjectId::compute(ObjectType::Blob, 'Hello, world!');
$id = ObjectId::compute(ObjectType::Blob, 'Hello, world!', 'sha256');

// Zero hash
$id = ObjectId::zero();
$id = ObjectId::zero('sha256');

// Properties
$id->hex;      // 40-character hex string (64 for SHA-256)
$id->binary;   // 20-byte raw binary (32 for SHA-256)
$id->algo;     // 'sha1' or 'sha256'
$id->isSha256();
$id->isZero();

// Comparison
$id->equals($otherId);
```

Το hash υπολογίζεται πάνω στα μη συμπιεσμένα δεδομένα: `sha1("{type} {size}\0{content}")` ή SHA-256 των ίδιων byte. Τα `fromHex()` και `fromBinary()` επιλέγουν τον αλγόριθμο με βάση το μήκος.

## Απαρίθμηση ObjectType

```php
use Pitmaster\Object\ObjectType;

ObjectType::Blob;    // 'blob'
ObjectType::Tree;    // 'tree'
ObjectType::Commit;  // 'commit'
ObjectType::Tag;     // 'tag'
```

## Μορφή loose αντικειμένων

Τα loose αντικείμενα αποθηκεύονται ως μεμονωμένα αρχεία στο `.git/objects/`, οργανωμένα με βάση τους δύο πρώτους δεκαεξαδικούς χαρακτήρες του hash τους.

```
.git/objects/a1/b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
```

Το περιεχόμενο του αρχείου είναι συμπιεσμένο με zlib. Το μη συμπιεσμένο περιεχόμενο είναι:

```
<type> <decimal size>\0<raw content>
```

Για παράδειγμα, ένα blob που περιέχει "Hello" αποθηκεύεται ως εξής:

```
zlib_encode("blob 5\0Hello")
```

### Ανάγνωση loose αντικειμένων

```php
use Pitmaster\Storage\LooseObjectStore;

$store = new LooseObjectStore('/path/to/.git/objects');
$object = $store->read($objectId);
```

Το `LooseObjectStore`:
1. Υπολογίζει τη διαδρομή του αρχείου από το hash
2. Διαβάζει και αποσυμπιέζει το αρχείο με zlib
3. Αναλύει την κεφαλίδα για να εξαγάγει τον τύπο και το μέγεθος
4. Αναθέτει την επεξεργασία στον κατάλληλο αναλυτή (`Blob`, `Tree`, `Commit`, `Tag`)

### Εγγραφή loose αντικειμένων

```php
$store->write($object);
```

Η διαδικασία εγγραφής:
1. Σειριοποίηση: `"{type} {size}\0{content}"`
2. Χρήση του `id` του αντικειμένου, που υπολογίζεται κατά τη δημιουργία του (οι αναγνώσεις επαληθεύουν το hash)
3. Συμπίεση: `zlib_encode(serialized)`
4. Εγγραφή στο `.git/objects/{hash[0..1]}/{rest of hash}`
5. Ατομική εγγραφή (εγγραφή σε προσωρινό αρχείο και έπειτα μετονομασία)

## ObjectSerializer

Το `ObjectSerializer` χειρίζεται την κωδικοποίηση και αποκωδικοποίηση της μορφής wire των αντικειμένων.

```php
use Pitmaster\Storage\ObjectSerializer;

// Encode
$raw = ObjectSerializer::encodeRaw($object);
// "blob 5\0Hello"
$compressed = ObjectSerializer::encode($object);
// zlib-compressed form, as stored in a loose object file

// Decode
$object = ObjectSerializer::decodeRaw($raw);
$object = ObjectSerializer::decode($compressed, $expectedHex); // throws CorruptObjectException on a hash mismatch
```

## ObjectDatabase

Το `ObjectDatabase` είναι ένας σύνθετος χώρος αποθήκευσης που αναζητά πρώτα loose αντικείμενα και έπειτα αρχεία pack.

```php
use Pitmaster\Storage\ObjectDatabase;

$db = new ObjectDatabase('/path/to/.git/objects');

$object = $db->read($objectId);    // Search loose, then packs
$db->write($object);               // Always writes to loose
$exists = $db->exists($objectId);  // Check loose, then packs
$all = $db->listAll();             // All hashes from loose + packs
```

Η εγγραφή απευθείας στον loose χώρο αποθήκευσης είναι σκόπιμη. Αφήστε το `git gc` να δημιουργήσει ξανά τα αρχεία pack.

## Υποστήριξη SHA-256

Το Pitmaster αφαιρεί την εξάρτηση από τον αλγόριθμο hash μέσω του `ObjectId`. Το SHA-1 είναι η προεπιλογή. Το SHA-256 επιλέγεται για κάθε αποθετήριο κατά τη δημιουργία του:

```php
$repo = Pitmaster::init('/path/to/project', 'sha256');
```

```bash
./vendor/bin/pitmaster init --object-format=sha256
```

Αυτό γράφει το `extensions.objectformat = sha256` στη ρύθμιση. Τα αποθετήρια που ανοίγονται αργότερα διαβάζουν τη μορφή από αυτήν την εγγραφή και, στη συνέχεια, κάθε λειτουργία αντικειμένου, tree, ευρετηρίου και αναφοράς χρησιμοποιεί δεκαεξαδικές συμβολοσειρές 64 χαρακτήρων και δυαδικά hash 32 byte. Δεν υπάρχει καθολικός διακόπτης ή σταθερά για τον αλγόριθμο.

Οι κλάσεις αντικειμένων δέχονται τον αλγόριθμο ως όρισμα όταν δημιουργείτε αντικείμενα οι ίδιοι: `Blob::fromContent($content, 'sha256')`, `Tree::fromEntries($entries, 'sha256')`, `ObjectId::compute($type, $content, 'sha256')`. Το `Pitmaster::clone()` δημιουργεί αποθετήρια SHA-1.

## Δυαδική μορφή εγγραφής tree

Μέσα στο περιεχόμενο ενός αντικειμένου tree, κάθε εγγραφή κωδικοποιείται ως εξής:

```
<octal mode as ASCII> <space> <filename> \0 <binary hash: 20 bytes SHA-1, 32 bytes SHA-256>
```

Σημείωση: το hash είναι ακατέργαστο δυαδικό, όχι δεκαεξαδικό, σε αντίθεση με τα δεκαεξαδικά hash στα αντικείμενα commit και tag.

Οι εγγραφές ταξινομούνται συγκρίνοντας τα ονόματα σαν οι κατάλογοι να έχουν στο τέλος `/`. Αυτή η σειρά ταξινόμησης πρέπει να είναι ακριβής, ώστε το hash του tree να ταιριάζει με τον υπολογισμό του git.
