
# Indeksformat

Indeksfilen (`.git/index`) er stagingområdet. Den registrerer de filer, der skal med i næste commit, sammen med metadata til effektiv beregning af status. Pitmaster læser indeksversion 2, 3 og 4 og skriver version 2 og 3. Hvis et indeks, der er læst som version 4, skrives, opstår der en fil, som git ikke kan læse ([#15](https://github.com/inline0/pitmaster/issues/15)), så konvertér sådanne repositories med `git update-index --index-version 2`, før du skriver gennem Pitmaster.

## Læsning af indekset

```php
use Pitmaster\Index\Index;

$index = Index::open('/path/to/.git/index');   // pass 32 as the second argument for SHA-256

// Or through the repository
$index = $repo->index();

// Entry count (all stages)
echo $index->count();

// Iterate stage 0 entries, keyed by path
foreach ($index->entries() as $path => $entry) {
    echo "{$entry->path} {$entry->hash->hex}\n";
}

// Look up a specific entry
$entry = $index->entry('src/File.php');
```

`Index::open()` returnerer et tomt indeks, hvis filen ikke findes. `entries()` returnerer kun poster på trin 0; `allEntries()` inkluderer konflikttrin, og `paths()` viser de sporede stier.

## IndexEntry

Hver post i indekset er et skrivebeskyttet værdiobjekt:

```php
use Pitmaster\Index\IndexEntry;

$entry->path;          // File path relative to repo root
$entry->hash;          // ObjectId of the blob
$entry->mode;          // File mode as an int (0100644, 0100755, 0120000, 0160000)
$entry->fileSize;      // File size in bytes
$entry->ctimeSec;      // Metadata change time (seconds)
$entry->ctimeNsec;     // Metadata change time nanoseconds
$entry->mtimeSec;      // Modification time (seconds)
$entry->mtimeNsec;     // Modification time nanoseconds
$entry->dev;           // Device number
$entry->ino;           // Inode number
$entry->uid;           // User ID
$entry->gid;           // Group ID
$entry->flags;         // Raw flags field
$entry->extendedFlags; // v3 extended flags (skip-worktree, intent-to-add)
$entry->stage();       // Conflict stage (0 = normal, 1 = base, 2 = ours, 3 = theirs)
$entry->assumeValid(); // Assume-valid bit
$entry->skipWorktree(); // Skip-worktree bit
```

### Oprettelse af poster

```php
// From file stat
$entry = IndexEntry::fromStat('src/File.php', $blobId, '/full/path/to/src/File.php');

// Minimal (no stat info)
$entry = IndexEntry::create('src/File.php', $blobId);

// With explicit mode
$entry = IndexEntry::create('deploy.sh', $blobId, 0100755);
```

## Ændring af indekset

```php
// Add or replace an entry
$index->addEntry($entry);

// Remove an entry
$index->removeEntry('src/OldFile.php');

// Replace all stages of a conflicted path with one resolved entry
$index->resolveConflict('src/File.php', $entry);
```

`addEntries()` og `removeEntries()` behandler flere poster eller stier i én omgang. Enhver ændring af posterne fjerner de gemte udvidelser (se nedenfor).

## Skrivning af indekset

```php
use Pitmaster\Index\IndexWriter;

IndexWriter::write($index, '/path/to/.git/index');
```

Eller gennem repositoryet (som håndterer dette automatisk):

```php
$repo->add('src/File.php');    // Reads file, creates blob, updates index, writes
$repo->remove('--cached', 'old-file.txt'); // Removes from index only, writes
```

## Binært format

### Header

```
Signature:   DIRC (4 bytes, ASCII)
Version:     4 bytes, big-endian (2, 3, or 4)
Entry count: 4 bytes, big-endian
```

### Postformat (v2)

Hver post består af:

```
ctime seconds:     4 bytes, big-endian
ctime nanoseconds: 4 bytes, big-endian
mtime seconds:     4 bytes, big-endian
mtime nanoseconds: 4 bytes, big-endian
dev:               4 bytes, big-endian
ino:               4 bytes, big-endian
mode:              4 bytes, big-endian
uid:               4 bytes, big-endian
gid:               4 bytes, big-endian
file size:         4 bytes, big-endian
object hash:       20 bytes SHA-1 or 32 bytes SHA-256 (raw binary)
flags:             2 bytes, big-endian
path:              variable length, NUL-terminated
padding:           1-8 NUL bytes to align to 8-byte boundary
```

Flagfeltet:
- Bit 15: flag for antag gyldig
- Bit 13-12: merge-trin (0-3)
- Bit 11-0: længde på stinavn eller 0xFFF, når stien er 4095 byte eller længere (læseren søger derefter efter NUL)

### Versionsforskelle

**Version 2**: grundformatet beskrevet ovenfor. Mest almindeligt.

**Version 3**: tilføjer udvidede flag (2 ekstra byte efter de almindelige flag). Understøtter bittene `skip-worktree` og `intent-to-add`. Bruges, når en post kræver udvidede flag.

**Version 4**: tilføjer komprimering af stipræfikser. I stedet for at gemme fulde stier gemmer hver post antallet af byte, der skal fjernes fra den forrige posts sti, efterfulgt af det nye suffiks. Reducerer indeksstørrelsen betydeligt for dybt indlejrede træer.

## Konflikttrin

Under en merge-konflikt kan én sti have flere indeks-poster på forskellige trin:

| Trin | Betydning |
|-------|---------|
| 0 | Normal (ingen konflikt) |
| 1 | Basisversion (fælles forfader) |
| 2 | Vores (aktuel gren) |
| 3 | Deres (gren, der merges) |

```php
// During a conflict, entries have non-zero stages
foreach ($index->allEntries() as $entry) {
    if ($entry->stage() > 0) {
        echo "Conflict: {$entry->path} (stage {$entry->stage()})\n";
    }
}

$index->hasUnmerged();            // true while conflicts remain
$index->unmergedPaths();          // conflicted paths
$index->stageEntries('a.txt');    // [1 => base, 2 => ours, 3 => theirs]
```

## Indeksudvidelser

Udvidelser tilføjes efter posterne og før kontrolsummen. Hver udvidelse har en signatur på 4 byte, en størrelse på 4 byte og data med variabel længde.

Pitmaster bevarer udvidelsesblokke som rå byte (`$index->extensions()` returnerer par af `signature` og `data`) og skriver dem uændret tilbage, når posterne ikke er ændret. Den fortolker eller genererer ikke nogen udvidelser, og enhver ændring af posterne fjerner dem alle, hvilket git accepterer og genopbygger efter behov. Udvidelserne, git bruger, beskrives nedenfor som reference.

### TREE-udvidelse

Cacher på forhånd beregnede træobjekter for mapper. Fremskynder `git status` og `git commit` ved at undgå genberegning af træer, når kun indekset er ændret.

Signatur: `TREE` (0x54524545)

### REUC-udvidelse

Registrerer oplysninger til fortrydelse af konfliktløsning. Når en konflikt er løst, flyttes de oprindelige poster på trin 1/2/3 hertil, så de kan gendannes med `git checkout -m`.

Signatur: `REUC` (0x52455543)

### Andre udvidelser

git skriver også:
- `EOIE` (slut på indeksindgangen): markerer, hvor poster slutter, og udvidelser begynder
- `IEOT` (offsettabel for indeksindgange): muliggør parallel indlæsning af indekset
- `link` (opdelt indeks): til meget store repositories, der bruger opdelt indeks

I git-formatet er udvidelser, hvis signatur begynder med et stort bogstav, valgfrie, mens dem med et lille bogstav er påkrævede. Pitmaster accepterer begge typer uden kontrol. Et opdelt indeks (`link`) indlæses ikke, så repositories, der bruger et, understøttes ikke.

## Kontrolsum

Indeksfilen slutter med en kontrolsum af alle foregående byte i repositoryets hashformat (20 byte SHA-1, 32 byte SHA-256). Pitmaster skriver den ved lagring, men verificerer den ikke ved læsning.

`Index::open()` og `Index::parse()` kaster `IndexParseException`, hvis signaturen på `DIRC` mangler, eller versionen ikke understøttes.

## Indeks og status

Indekset er centralt for beregning af status. `WorkingTreeStatus` sammenligner:
1. HEAD-træ med indeks: registrerer staged ændringer
2. Indeks med arbejdstræ: registrerer unstaged ændringer

Stat-felterne (ctime, mtime, dev, ino, size, mode, uid, gid) muliggør hurtige kontroller af, om en fil er ændret, uden at læse filindholdet. Hvis stat-felterne stemmer, og filen blev ændret før statusscanningen begyndte, antages filen at være uændret. En anden størrelse markerer den straks som ændret. Ellers læser Pitmaster filen og beregner dens hash for at kontrollere, om indholdet faktisk er ændret.

## Flaget antag gyldig

```php
if ($entry->assumeValid()) {
    // Entry has assume-valid set (flags & 0x8000)
}
```

Dette flag fortæller git, at filen skal springes over ved statustjek, selv hvis stat-felterne er ændret (`git update-index --assume-unchanged`). Pitmaster bevarer bitten, når poster omskrives, men dens statusfunktion tager ikke hensyn til den og sammenligner stadig filen.
