
# Git objekti

Katrs objekts git repozitorijā tiek glabāts kā atsevišķs objekts. Ir četri veidi: blob (faila saturs), koki (direktoriju saraksti), komiti (momentuzņēmumi ar metadatiem) un tagi (anotētas atsauces). Katru objektu identificē tā satura SHA-1 jaucējvērtība.

## Objektu veidi

### Blob

Blob satur neapstrādātu faila saturu bez metadatiem (bez faila nosaukuma un atļaujām).

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

### Koks

Koks ir direktorijas saraksts. Katram ierakstam ir režīms, nosaukums un jaucējvērtība, kas norāda uz blob vai apakškoku.

```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()` ieraksta vienumus norādītajā secībā un režīmu virknes tieši tādas, kā norādīts, tāpēc vispirms tās sakārtojiet un direktoriju režīmus norādiet kā `40000`. Koks, kas ierakstīts ar `040000` vai citā secībā, iegūst citādu jaucējvērtību nekā git, un `git fsck --strict` izvada režīmu ar nullēm sākumā.

#### TreeEntry

`TreeEntry` ir tikai lasāms vērtības objekts:

```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žīmu vērtības:
| Režīms | Nozīme |
|------|---------|
| `100644` | Parasts fails |
| `100755` | Izpildāms fails |
| `40000` | Direktorija (koks); `git ls-tree` to rāda kā `040000` |
| `120000` | Simboliskā saite |
| `160000` | Gitlink (apakšmodulis) |

Koka ieraksti tiek sakārtoti pēc nosaukuma, salīdzināšanas nolūkos pieņemot, ka direktoriju nosaukumu beigās ir `/`.

### Komits

Komits sasaista koku ar tā vēsturi un metadatiem.

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

#### Komita satura veidošana

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

Neapstrādāta komita formāts:

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

Anotēti tagi ir objekti ar metadatiem.

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

Neapstrādāts taga formāts:

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

## ObjectId

`ObjectId` ir tikai lasāms vērtības objekts, kas attēlo SHA-1 (vai SHA-256) jaucējvērtību.

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

Jaucējvērtība tiek aprēķināta no nesaspiestajiem datiem: `sha1("{type} {size}\0{content}")` vai tādu pašu baitu SHA-256. `fromHex()` un `fromBinary()` izvēlas algoritmu pēc garuma.

## ObjectType uzskaitījums

```php
use Pitmaster\Object\ObjectType;

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

## Atsevišķu objektu formāts

Atsevišķi objekti tiek glabāti kā atsevišķi faili mapē `.git/objects/`, sakārtoti pēc pirmajām divām savas jaucējvērtības heksadecimālajām rakstzīmēm.

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

Faila saturs ir saspiests ar zlib. Nesaspiestais saturs ir šāds:

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

Piemēram, blob, kas satur “Hello”, tiek saglabāts šādi:

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

### Atsevišķu objektu nolasīšana

```php
use Pitmaster\Storage\LooseObjectStore;

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

`LooseObjectStore`:
1. Aprēķina faila ceļu pēc jaucējvērtības
2. Nolasa un atspiež failu ar zlib
3. Parsē galveni, lai iegūtu veidu un izmēru
4. Nodod attiecīgajam parsētājam (`Blob`, `Tree`, `Commit`, `Tag`)

### Atsevišķu objektu ierakstīšana

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

Ierakstīšanas process:
1. Serializēt: `"{type} {size}\0{content}"`
2. Izmantot objekta `id`, kas aprēķināts objekta izveides laikā (nolasot jaucējvērtība tiek pārbaudīta)
3. Saspiest: `zlib_encode(serialized)`
4. Ierakstīt mapē `.git/objects/{hash[0..1]}/{rest of hash}`
5. Veikt atomisku ierakstīšanu (ierakstīt pagaidu failā un pēc tam pārdēvēt)

## ObjectSerializer

`ObjectSerializer` apstrādā objekta vadu formāta kodēšanu un dekodēšanu.

```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` ir kombinēta krātuve, kas vispirms meklē atsevišķos objektus un pēc tam pakotņu failos.

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

Rakstīšana tieši atsevišķo objektu krātuvē ir apzināta izvēle. Ļaujiet `git gc` pārpakot objektus pakotņu failos.

## SHA-256 atbalsts

Pitmaster abstrahē jaucējalgoritmu, izmantojot `ObjectId`. SHA-1 ir noklusējums. SHA-256 tiek izvēlēts katram repozitorijam tā izveides laikā:

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

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

Tādējādi konfigurācijā tiek ierakstīts `extensions.objectformat = sha256`. Vēlāk atvērtie repozitoriji nolasa formātu no šī ieraksta, un visas objektu, koku, indeksa un atsauču darbības pēc tam izmanto 64 rakstzīmju heksadecimālas virknes un 32 baitu bināras jaucējvērtības. Algoritmam nav globāla slēdža vai konstantes.

Veidojot objektus pašiem, objektu klases pieņem algoritmu kā argumentu: `Blob::fromContent($content, 'sha256')`, `Tree::fromEntries($entries, 'sha256')`, `ObjectId::compute($type, $content, 'sha256')`. `Pitmaster::clone()` izveido SHA-1 repozitorijus.

## Koka ieraksta binārais formāts

Koka objekta saturā katrs ieraksts tiek kodēts šādi:

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

Piezīme: jaucējvērtība ir neapstrādāti bināri dati, nevis heksadecimāla virkne, atšķirībā no komita un taga objektu heksadecimālajām jaucējvērtībām.

Ieraksti tiek sakārtoti, salīdzinot nosaukumus tā, it kā direktorijām beigās būtu `/`. Šai secībai jābūt precīzai, lai koka jaucējvērtība atbilstu git aprēķinātajai.
