
# Git objektai

Viskas git saugykloje saugoma kaip objektas. Yra keturi tipai: blob objektai (failų turinys), medžių objektai (katalogų sąrašai), pakeitimai (momentinės kopijos su metaduomenimis) ir žymos (anotuotos nuorodos). Kiekvienas objektas identifikuojamas pagal jo turinio SHA-1 maišą.

## Objektų tipai

### Blob

Blob saugo neapdorotą failo turinį be metaduomenų (be failo pavadinimo ir teisių).

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

Tree yra katalogų sąrašas. Kiekvienas įrašas turi režimą, pavadinimą ir maišą, nurodančią blob arba žemesnio lygio tree.

```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()` įrašo pateiktus įrašus nurodyta tvarka ir režimų eilutes tiksliai taip, kaip jos pateiktos, todėl pirmiausia jas surikiuokite, o katalogų režimus nurodykite kaip `40000`. Tree, įrašytas naudojant `040000` arba kita tvarka, turės kitokią maišą nei git, o `git fsck --strict` pateikia režimą su nuliais priekyje.

#### TreeEntry

`TreeEntry` yra tik skaitomas reikšmės objektas:

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

Režimų reikšmės:
| Režimas | Reikšmė |
|------|---------|
| `100644` | Įprastas failas |
| `100755` | Vykdomasis failas |
| `40000` | Katalogas (tree); `git ls-tree` rodo kaip `040000` |
| `120000` | Simbolinė nuoroda |
| `160000` | Gitlink (submodulis) |

Tree įrašai rūšiuojami pagal pavadinimą; lyginant katalogų pavadinimus laikoma, kad jų gale yra `/`.

### Commit

Commit susieja tree su jo istorija ir metaduomenimis.

```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 turinio kūrimas

```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",
);
```

Neapdorotas commit formatas:

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

Anotuoti tag yra objektai su metaduomenimis.

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

Neapdorotas tag formatas:

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

## ObjectId

`ObjectId` yra tik skaitomas reikšmės objektas, atitinkantis SHA-1 (arba SHA-256) maišą.

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

Maiša apskaičiuojama pagal nesuglaudintus duomenis: `sha1("{type} {size}\0{content}")` arba SHA-256 iš tų pačių baitų. `fromHex()` ir `fromBinary()` algoritmą parenka pagal ilgį.

## ObjectType išvardijimas

```php
use Pitmaster\Object\ObjectType;

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

## Laisvųjų objektų formatas

Laisvieji objektai saugomi kaip atskiri failai kataloge `.git/objects/`, suskirstyti pagal pirmuosius du jų maišos šešioliktainius simbolius.

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

Failo turinys suglaudinamas naudojant zlib. Nesuglaudintas turinys:

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

Pavyzdžiui, blob, kuriame yra „Hello“, saugomas taip:

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

### Laisvųjų objektų skaitymas

```php
use Pitmaster\Storage\LooseObjectStore;

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

`LooseObjectStore`:
1. Apskaičiuoja failo kelią pagal maišą
2. Perskaito failą ir išskleidžia zlib suglaudintus duomenis
3. Išanalizuoja antraštę, kad gautų tipą ir dydį
4. Perduoda duomenis atitinkamam analizatoriui (`Blob`, `Tree`, `Commit`, `Tag`)

### Laisvųjų objektų įrašymas

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

Įrašymo eiga:
1. Serializavimas: `"{type} {size}\0{content}"`
2. Naudojama objekto `id`, apskaičiuota jį sukūrus (skaitant maiša patikrinama)
3. Suspaudimas: `zlib_encode(serialized)`
4. Įrašymas į `.git/objects/{hash[0..1]}/{rest of hash}`
5. Atominis įrašymas (įrašoma į laikiną failą, tada jis pervadinamas)

## ObjectSerializer

`ObjectSerializer` tvarko objekto perdavimo formato kodavimą ir dekodavimą.

```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` yra sudėtinė saugykla, kuri pirmiausia ieško laisvųjų objektų, tada paketo failuose.

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

Rašymas tiesiai į laisvųjų objektų saugyklą yra tyčinis. Leiskite `git gc` pergrupuoti objektus į paketo failus.

## SHA-256 palaikymas

Pitmaster maišos algoritmą abstrahuoja per `ObjectId`. Pagal numatytuosius nustatymus naudojama SHA-1. SHA-256 parenkama kuriant saugyklą:

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

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

Taip `extensions.objectformat = sha256` įrašomas į konfigūraciją. Vėliau atidarytos saugyklos formatą nuskaito iš šio įrašo, o visos objektų, tree, indekso ir nuorodų operacijos naudoja 64 simbolių šešioliktaines eilutes ir 32 baitų dvejetaines maišas. Nėra bendrojo jungiklio ar konstantos, skirtos algoritmui pakeisti.

Kuriant objektus rankiniu būdu, objekto klasėms algoritmas perduodamas kaip argumentas: `Blob::fromContent($content, 'sha256')`, `Tree::fromEntries($entries, 'sha256')`, `ObjectId::compute($type, $content, 'sha256')`. `Pitmaster::clone()` kuria SHA-1 saugyklas.

## Tree įrašo dvejetainis formatas

Tree objekto turinyje kiekvienas įrašas koduojamas taip:

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

Pastaba: maiša yra neapdorota dvejetainė seka, o ne šešioliktainė, priešingai nei commit ir tag objektuose esančios šešioliktainės maišos.

Įrašai rūšiuojami lyginant pavadinimus taip, tarsi katalogų pavadinimų gale būtų `/`. Ši tvarka turi būti tiksli, kad tree maiša sutaptų su git apskaičiuota maiša.
