
# Obiecte Git

Totul într-un git este stocat ca obiect. Există patru tipuri: bloburi (conținutul fișierelor), arbori (liste de directoare), commituri (instantanee cu metadate) și taguri (referințe adnotate). Fiecare obiect este identificat prin SHA-1 conținutului său.

## Tipuri de obiecte

### Blob

Un blob conține conținutul brut al unui fișier, fără metadate (nume de fișier sau permisiuni).

```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)
```

### Arbore

Un arbore este o listă de directoare. Fiecare intrare are un mod, un nume și un hash care indică spre un blob sau un subarbore.

```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()` scrie intrările în ordinea dată și șirurile de mod exact așa cum sunt furnizate, așa că sortați-le mai întâi și scrieți modurile directoarelor ca `40000`. Un arbore scris cu `040000` sau în altă ordine primește un hash diferit de cel al git, iar `git fsck --strict` raportează modul completat cu zerouri la stânga.

#### TreeEntry

`TreeEntry` este un obiect valoare doar pentru citire:

```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)
```

Valori pentru moduri:
| Mod | Semnificație |
|------|---------|
| `100644` | Fișier obișnuit |
| `100755` | Fișier executabil |
| `40000` | Director (arbore); afișat ca `040000` de `git ls-tree` |
| `120000` | Legătură simbolică |
| `160000` | Gitlink (submodul) |

Intrările arborelui sunt sortate după nume, iar numele directoarelor sunt tratate ca și cum s-ar termina cu `/` în scopul comparației.

### Commit

Un commit leagă un arbore de istoricul și metadatele sale.

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

#### Construirea conținutului unui 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",
);
```

Formatul brut al unui 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>
```

### Tag

Tagurile adnotate sunt obiecte cu metadate.

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

Formatul brut al unui tag:

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

## ObjectId

`ObjectId` este un obiect valoare doar pentru citire care reprezintă un hash SHA-1 (sau 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);
```

Hashul este calculat pe baza datelor necomprimate: `sha1("{type} {size}\0{content}")` sau SHA-256 ai acelorași octeți. `fromHex()` și `fromBinary()` aleg algoritmul în funcție de lungime.

## Enum ObjectType

```php
use Pitmaster\Object\ObjectType;

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

## Formatul obiectelor loose

Obiectele loose sunt stocate ca fișiere individuale în `.git/objects/`, organizate după primele două caractere hexazecimale ale hashului.

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

Conținutul fișierului este comprimat cu zlib. Conținutul necomprimat este:

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

De exemplu, un blob care conține „Hello” este stocat astfel:

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

### Citirea obiectelor loose

```php
use Pitmaster\Storage\LooseObjectStore;

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

`LooseObjectStore`:
1. Calculează calea fișierului din hash
2. Citește și decomprimă fișierul cu zlib
3. Analizează antetul pentru a extrage tipul și dimensiunea
4. Deleagă procesarea către analizatorul corespunzător (`Blob`, `Tree`, `Commit`, `Tag`)

### Scrierea obiectelor loose

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

Procesul de scriere:
1. Serializare: `"{type} {size}\0{content}"`
2. Folosiți `id` obiectului, calculat la construirea acestuia (citirile verifică hashul)
3. Comprimare: `zlib_encode(serialized)`
4. Scriere în `.git/objects/{hash[0..1]}/{rest of hash}`
5. Scriere atomică (scriere într-un fișier temporar, apoi redenumire)

## ObjectSerializer

`ObjectSerializer` gestionează codificarea și decodificarea formatului wire al obiectului.

```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` este un depozit compozit care caută mai întâi obiectele loose, apoi fișierele 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
```

Scrierea directă în stocarea loose este intenționată. Lăsați `git gc` să împacheteze din nou obiectele în fișiere pack.

## Compatibilitate cu SHA-256

Pitmaster abstractizează algoritmul hash prin `ObjectId`. SHA-1 este valoarea implicită. SHA-256 este ales pentru fiecare depozit la crearea acestuia:

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

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

Acest lucru scrie `extensions.objectformat = sha256` în configurație. Depozitele deschise ulterior citesc formatul din acea intrare, iar fiecare operație asupra obiectelor, arborilor, indexului și referințelor folosește apoi șiruri hexazecimale de 64 de caractere și hashuri binare de 32 de octeți. Nu există un comutator global sau o constantă pentru algoritm.

Clasele de obiecte primesc algoritmul ca argument atunci când construiți singuri obiecte: `Blob::fromContent($content, 'sha256')`, `Tree::fromEntries($entries, 'sha256')`, `ObjectId::compute($type, $content, 'sha256')`. `Pitmaster::clone()` creează depozite SHA-1.

## Formatul binar al intrărilor de arbore

În conținutul unui obiect arbore, fiecare intrare este codificată astfel:

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

Notă: hashul este binar brut, nu hexazecimal, spre deosebire de hashurile hexazecimale din obiectele commit și tag.

Intrările sunt sortate comparând numele ca și cum directoarele ar avea la final `/`. Ordinea de sortare trebuie să fie exactă pentru ca hashul arborelui să corespundă calculului efectuat de git.
