
# Indexformat

Indexfilen (`.git/index`) är mellanlagringsområdet. Den registrerar filerna som ska ingå i nästa commit samt metadata för effektiv statusberäkning. Pitmaster läser indexversionerna 2, 3 och 4 och skriver versionerna 2 och 3. Om du skriver ett index som lästes som version 4 skapas en fil som git inte kan läsa ([#15](https://github.com/inline0/pitmaster/issues/15)). Konvertera därför sådana arkiv med `git update-index --index-version 2` innan du skriver genom Pitmaster.

## Läsa indexet

```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()` returnerar ett tomt index om filen inte finns. `entries()` returnerar endast poster i steg 0; `allEntries()` inkluderar konfliktsteg, och `paths()` listar de spårade sökvägarna.

## IndexEntry

Varje post i indexet är ett skrivskyddat värdeobjekt:

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

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

## Ändra indexet

```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()` och `removeEntries()` hanterar flera poster eller sökvägar i ett svep. Alla ändringar av posterna tar bort de lagrade tilläggen (se nedan).

## Skriva indexet

```php
use Pitmaster\Index\IndexWriter;

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

Eller via arkivet (som hanterar detta automatiskt):

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

### Huvud

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

### Postformat (v2)

Varje post består av:

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

Flaggfältet:
- Bit 15: flaggan assume-valid
- Bitar 13–12: merge-steg (0–3)
- Bitar 11–0: sökvägens längd, eller 0xFFF när sökvägen är minst 4095 byte lång (läsaren söker då efter NUL)

### Skillnader mellan versionerna

**Version 2**: grundformatet som beskrivs ovan. Vanligast.

**Version 3**: lägger till utökade flaggor (2 extra byte efter de vanliga flaggorna). Stöder bitarna `skip-worktree` och `intent-to-add`. Används när någon post behöver utökade flaggor.

**Version 4**: lägger till komprimering av sökvägsprefix. I stället för att lagra fullständiga sökvägar lagrar varje post antalet byte som ska tas bort från föregående posts sökväg, följt av det nya suffixet. Minskar indexets storlek avsevärt för djupt nästlade träd.

## Konfliktsteg

Under en merge-konflikt kan en enda sökväg ha flera indexposter i olika steg:

| Steg | Betydelse |
|-------|---------|
| 0 | Normal (ingen konflikt) |
| 1 | Basversion (gemensam förfader) |
| 2 | Vår version (aktuell gren) |
| 3 | Deras version (grenen som sammanfogas) |

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

## Indextillägg

Tillägg läggs till efter posterna och före kontrollsumman. Varje tillägg har en signatur på 4 byte, en storlek på 4 byte och data med variabel längd.

Pitmaster behåller tilläggsblock som råa byte (`$index->extensions()` returnerar paren `signature` och `data`) och skriver tillbaka dem oförändrade om posterna inte har ändrats. Den tolkar eller skapar inga tillägg, och alla ändringar av posterna tar bort dem; detta godtas av git, som återskapar tilläggen vid behov. Tilläggen som används av git beskrivs nedan som referens.

### TREE-tillägg

Lagrar cachelagrade, förberäknade trädobjekt för kataloger. Snabbar upp `git status` och `git commit` genom att undvika att beräkna om träd när bara indexet har ändrats.

Signatur: `TREE` (0x54524545)

### REUC-tillägg

Registrerar information för att ångra konfliktlösning. När en konflikt har lösts flyttas de ursprungliga posterna i steg 1/2/3 hit, så att de kan återställas med `git checkout -m`.

Signatur: `REUC` (0x52455543)

### Övriga tillägg

git skriver också:
- `EOIE` (slut på indexpost): markerar var posterna slutar och tilläggen börjar
- `IEOT` (förskjutningstabell för indexposter): möjliggör parallell inläsning av indexet
- `link` (delat index): för mycket stora arkiv som använder delat index

I gits format är tillägg vars signatur börjar med en versal valfria, medan tillägg med gemener är obligatoriska. Pitmaster godtar båda typerna utan kontroll. Ett delat index (`link`) läses inte in, så arkiv som använder det stöds inte.

## Kontrollsumma

Indexfilen avslutas med en kontrollsumma för alla föregående byte, beräknad med arkivets hash (20 byte för SHA-1, 32 byte för SHA-256). Pitmaster skriver den när indexet sparas men verifierar den inte vid inläsning.

`Index::open()` och `Index::parse()` kastar `IndexParseException` om signaturen `DIRC` saknas eller om versionen inte stöds.

## Index och status

Indexet är centralt för statusberäkningen. `WorkingTreeStatus` jämför:
1. HEAD-träd mot index: upptäcker fasade ändringar
2. Index mot arbetskatalog: upptäcker ofasade ändringar

Stat-fälten (ctime, mtime, dev, ino, size, mode, uid, gid) möjliggör snabba kontroller av om en fil har ändrats, utan att läsa filinnehållet. Om stat-fälten matchar och filen ändrades senast före statusgenomsökningen antas filen vara oförändrad. En annan storlek markerar den omedelbart som ändrad. Annars läser Pitmaster filen och beräknar dess hash för att kontrollera om innehållet faktiskt har ändrats.

## Flaggan assume-valid

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

Flaggan talar om för git att hoppa över kontrollen av filen vid statusavläsning, även om stat-fälten har ändrats (`git update-index --assume-unchanged`). Pitmaster behåller biten när poster skrivs om, men statusfunktionen tar inte hänsyn till den och jämför ändå filen.
