
# Git-objekter

Alt i et git-arkiv gemmes som et objekt. Der findes fire typer: blobs (filindhold), trees (biblioteksoversigter), commits (snapshots med metadata) og tags (kommenterede referencer). Hvert objekt identificeres ved indholdets SHA-1-hash.

## Objekttyper

### Blob

En blob indeholder råt filindhold uden metadata (intet filnavn, ingen tilladelser).

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

Et tree er en mappefortegnelse. Hver post har en tilstand, et navn og en hash, der peger på en blob eller et undertree.

```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()` skriver posterne i den angivne rækkefølge og tilstandsstrengene præcis som angivet, så sortér dem først, og skriv mappetilstande som `40000`. Et tree skrevet med `040000` eller i en anden rækkefølge får en anden hash end git, og `git fsck --strict` rapporterer tilstanden med foranstillede nuller.

#### TreeEntry

`TreeEntry` er et skrivebeskyttet værdiobjekt:

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

Tilstandsværdier:
| Tilstand | Betydning |
|------|---------|
| `100644` | Almindelig fil |
| `100755` | Eksekverbar fil |
| `40000` | Mappe (tree); vises som `040000` af `git ls-tree` |
| `120000` | Symbolsk link |
| `160000` | Gitlink (submodul) |

Tree-poster sorteres efter navn, hvor mappenavne behandles, som om de slutter med `/` ved sammenligning.

### Commit

En commit knytter et tree til dets historik og metadata.

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

#### Opbygning af commit-indhold

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

Det rå commit-format:

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

Annoterede tags er objekter med metadata.

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

Råt tag-format:

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

## ObjectId

`ObjectId` er et skrivebeskyttet værdiobjekt, der repræsenterer en hash af typen SHA-1 (eller 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);
```

Hashen beregnes over de ukomprimerede data: `sha1("{type} {size}\0{content}")` eller SHA-256 af de samme byte. `fromHex()` og `fromBinary()` vælger algoritmen ud fra længden.

## ObjectType-enum

```php
use Pitmaster\Object\ObjectType;

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

## Løst objektformat

Løse objekter gemmes som individuelle filer i `.git/objects/`, organiseret efter de første to hexadecimale tegn i deres hash.

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

Filindholdet er zlib-komprimeret. Det ukomprimerede indhold er:

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

For eksempel gemmes en blob med indholdet "Hello" som:

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

### Læsning af løse objekter

```php
use Pitmaster\Storage\LooseObjectStore;

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

`LooseObjectStore`:
1. Beregner filstien ud fra hashen
2. Læser og zlib-dekomprimerer filen
3. Analyserer headeren for at udtrække type og størrelse
4. Overdrager behandlingen til den relevante parser (`Blob`, `Tree`, `Commit`, `Tag`)

### Skrivning af løse objekter

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

Skriveprocessen:
1. Serialisér: `"{type} {size}\0{content}"`
2. Brug objektets `id`, beregnet, da objektet blev opbygget (læsninger verificerer hashen)
3. Komprimér: `zlib_encode(serialized)`
4. Skriv til `.git/objects/{hash[0..1]}/{rest of hash}`
5. Atomisk skrivning (skriv til en midlertidig fil, og omdøb den derefter)

## ObjectSerializer

`ObjectSerializer` håndterer kodning og afkodning af objektets wire-format.

```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` er et sammensat lager, der først søger efter løse objekter og derefter i pack-filer.

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

Gennemskrivning til løst lager er tilsigtet. Lad `git gc` pakke objekterne om i pack-filer.

## Understøttelse af SHA-256

Pitmaster abstraherer hash-algoritmen gennem `ObjectId`. SHA-1 er standarden. SHA-256 vælges for hvert repository, når det oprettes:

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

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

Dette skriver `extensions.objectformat = sha256` til konfigurationen. Repositories, der åbnes senere, læser formatet fra denne post, og alle handlinger med objekter, træer, indeks og refs bruger derefter hexadecimale strenge på 64 tegn og binære hasher på 32 byte. Der findes ingen global kontakt eller konstant for algoritmen.

Objektklasserne tager algoritmen som argument, når du selv opbygger objekter: `Blob::fromContent($content, 'sha256')`, `Tree::fromEntries($entries, 'sha256')`, `ObjectId::compute($type, $content, 'sha256')`. `Pitmaster::clone()` opretter SHA-1-repositories.

## Binært format for tree-poster

I indholdet af et tree-objekt kodes hver post som:

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

Bemærk: Hashen er rå binær, ikke hex, i modsætning til hex-hashene i commit- og tag-objekter.

Poster sorteres ved at sammenligne navne, som om mapper har et afsluttende `/`. Sorteringsrækkefølgen skal være præcis, for at tree-hashen matcher git-beregningen.
