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). Konvertera därför sådana arkiv med git update-index --index-version 2 innan du skriver genom Pitmaster.
Läsa indexet
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:
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
// 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
// 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
use Pitmaster\Index\IndexWriter;
IndexWriter::write($index, '/path/to/.git/index');
Eller via arkivet (som hanterar detta automatiskt):
$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) |
// 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örjarIEOT(förskjutningstabell för indexposter): möjliggör parallell inläsning av indexetlink(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:
- HEAD-träd mot index: upptäcker fasade ändringar
- 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
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.