
# Indexformátum

Az indexfájl (`.git/index`) az előkészítési terület. Rögzíti a következő commitba kerülő fájlokat, valamint a hatékony állapotkiszámításhoz szükséges metaadatokat. A Pitmaster a 2-es, 3-as és 4-es indexverziót olvassa, a 2-es és 3-as verziót pedig írja. A 4-es verzióként beolvasott index írása olyan fájlt eredményez, amelyet a git nem tud beolvasni ([#15](https://github.com/inline0/pitmaster/issues/15)); ezért az ilyen tárolókat a `git update-index --index-version 2` paranccsal alakítsa át, mielőtt a Pitmaster segítségével írná őket.

## Az index beolvasása

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

A `Index::open()` üres indexet ad vissza, ha a fájl nem létezik. A `entries()` csak a 0-s állapotú bejegyzéseket adja vissza; a `allEntries()` a konfliktusállapotokat is tartalmazza, a `paths()` pedig felsorolja a követett útvonalakat.

## IndexEntry

Az index minden bejegyzése csak olvasható értékobjektum:

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

### Bejegyzések létrehozása

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

## Az index módosítása

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

A `addEntries()` és a `removeEntries()` több bejegyzést vagy útvonalat dolgoz fel egy menetben. A bejegyzések bármilyen módosítása törli a tárolt kiterjesztéseket (lásd alább).

## Az index írása

```php
use Pitmaster\Index\IndexWriter;

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

Vagy a tárolón keresztül (amely ezt automatikusan kezeli):

```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áris formátum

### Fejléc

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

### Bejegyzésformátum (v2)

Minden bejegyzés felépítése:

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

A jelzőbitek mezője:
- 15. bit: érvényesnek tekintési jelző
- 13–12. bit: egyesítési állapot (0–3)
- 11–0. bit: az útvonalnév hossza, vagy 0xFFF, ha az útvonal legalább 4095 bájt hosszú (ekkor a beolvasó a NUL bájtig keres)

### Verziók közötti különbségek

**2-es verzió**: a fent leírt alapformátum. A leggyakoribb.

**3-as verzió**: kiterjesztett jelzőbitekkel egészül ki (2 további bájt a normál jelzők után). Támogatja a `skip-worktree` és `intent-to-add` biteket. Akkor használatos, ha valamelyik bejegyzéshez kiterjesztett jelzőbitek szükségesek.

**4-es verzió**: útvonalprefix-tömörítéssel egészül ki. A teljes útvonalak tárolása helyett minden bejegyzés az előző bejegyzés útvonalából eltávolítandó bájtok számát, majd az új utótagot tárolja. Jelentősen csökkenti az index méretét mélyen egymásba ágyazott fák esetén.

## Konfliktusállapotok

Egyesítési konfliktus esetén egyetlen útvonalhoz több, különböző állapotú indexbejegyzés is tartozhat:

| Állapot | Jelentés |
|-------|---------|
| 0 | Normál (nincs konfliktus) |
| 1 | Alapverzió (közös ős) |
| 2 | Saját verzió (aktuális ág) |
| 3 | Másik verzió (egyesítés alatt álló ág) |

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

## Indexkiterjesztések

A kiterjesztések a bejegyzések után, az ellenőrző összeg előtt következnek. Minden kiterjesztés 4 bájtos aláírásból, 4 bájtos méretből és változó hosszúságú adatokból áll.

A Pitmaster nyers bájtokként őrzi meg a kiterjesztésblokkokat (a `$index->extensions()` `signature` és `data` párokat ad vissza), és változatlanul írja vissza őket, ha a bejegyzések nem módosultak. Nem értelmezi és nem állítja elő a kiterjesztéseket; a bejegyzések bármilyen módosításakor törli az összeset, amit a git elfogad, és szükség szerint újraépít. A git által használt kiterjesztéseket alább referenciaként ismertetjük.

### TREE-kiterjesztés

Előre kiszámított faobjektumokat gyorsítótáraz könyvtárakhoz. Felgyorsítja a `git status` és a `git commit` működését, mert elkerüli a fa újraszámítását, ha csak az index változott.

Aláírás: `TREE` (0x54524545)

### REUC-kiterjesztés

A visszavonási információkat rögzíti. Egy konfliktus feloldása után az eredeti 1/2/3-as állapotú bejegyzések ide kerülnek, hogy a `git checkout -m` paranccsal visszaállíthatók legyenek.

Aláírás: `REUC` (0x52455543)

### Egyéb kiterjesztések

A git a következőket is írja:
- `EOIE` (az indexbejegyzések vége): jelöli a bejegyzések végét és a kiterjesztések kezdetét
- `IEOT` (indexbejegyzés-eltolástábla): lehetővé teszi az index párhuzamos betöltését
- `link` (osztott index): nagy, osztott indexet használó tárolókhoz

A git formátumában azok a kiterjesztések választhatók, amelyek aláírása nagybetűvel kezdődik; a kisbetűvel kezdődők kötelezők. A Pitmaster ellenőrzés nélkül elfogadja mindkét típust. Az osztott index (`link`) nem töltődik be, ezért az azt használó tárolók nem támogatottak.

## Ellenőrző összeg

Az indexfájl a tároló hash-algoritmusával számított, minden korábbi bájtra kiterjedő ellenőrző összeggel zárul (20 bájt SHA-1 esetén, 32 bájt SHA-256 esetén). A Pitmaster mentéskor kiírja, de beolvasáskor nem ellenőrzi.

A `Index::open()` és a `Index::parse()` `IndexParseException` hibát dob, ha hiányzik a `DIRC` aláírás, vagy nem támogatott verzióval találkozik.

## Index és állapot

Az index központi szerepet játszik az állapot kiszámításában. A `WorkingTreeStatus` összehasonlítja:
1. HEAD fa és index: az előkészített módosítások észlelése
2. Index és munkafa: az elő nem készített módosítások észlelése

A stat mezők (ctime, mtime, dev, ino, size, mode, uid, gid) lehetővé teszik annak gyors ellenőrzését, hogy „megváltozott-e ez a fájl?”, a fájltartalom beolvasása nélkül. Ha a stat mezők megegyeznek, és a fájl az állapotvizsgálat kezdete előtt módosult utoljára, a fájl változatlannak tekinthető. Az eltérő méret azonnal módosítottnak jelöli. Egyébként a Pitmaster beolvassa a fájlt, és kiszámítja a hash értékét, hogy ellenőrizze, valóban változott-e a tartalma.

## Érvényesnek tekintési jelző

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

Ez a jelző arra utasítja a gitet, hogy hagyja ki a fájl ellenőrzését az állapotvizsgálat során akkor is, ha a stat mezők megváltoztak (`git update-index --assume-unchanged`). A Pitmaster a bejegyzések újraírásakor megtartja ezt a bitet, de az állapotvizsgálata nem veszi figyelembe, és továbbra is összehasonlítja a fájlt.
