Preskoči na vsebino

Oblika indeksa

Datoteka indeksa (.git/index) je območje priprave. Zabeleži datoteke, ki bodo vključene v naslednji potrditveni zapis, skupaj z metapodatki za učinkovito izračunavanje stanja. Pitmaster bere različice indeksa 2, 3 in 4 ter zapisuje različici 2 in 3. Zapis indeksa, prebranega kot različica 4, ustvari datoteko, ki je git ne more prebrati (#15), zato take repozitorije pred zapisovanjem prek Pitmaster pretvorite z git update-index --index-version 2.

Branje indeksa

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() vrne prazen indeks, če datoteka ne obstaja. entries() vrne samo vnose stopnje 0; allEntries() vključuje stopnje sporov, paths() pa izpiše sledene poti.

IndexEntry

Vsak vnos v indeksu je nespremenljiv objekt vrednosti:

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

Ustvarjanje vnosov

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

Spreminjanje indeksa

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() in removeEntries() v enem prehodu obdelata več vnosov ali poti. Vsaka sprememba vnosov odstrani shranjene razširitve (glejte spodaj).

Zapisovanje indeksa

PHP
use Pitmaster\Index\IndexWriter;

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

Ali prek repozitorija (ki to uredi samodejno):

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

Binarna oblika

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

Oblika vnosa (v2)

Vsak vnos je sestavljen takole:

Koda
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

Polje zastavic:

  • Bit 15: zastavica »predpostavi, da je veljavno«
  • Bita 13–12: stopnja združitve (0–3)
  • Biti 11–0: dolžina imena poti ali 0xFFF, kadar je pot dolga 4095 bajtov ali več (bralnik nato poišče NUL)

Razlike med različicami

Različica 2: osnovna oblika, opisana zgoraj. Najpogostejša.

Različica 3: doda razširjene zastavice (2 dodatna bajta za običajnimi zastavicami). Podpira bita skip-worktree in intent-to-add. Uporablja se, kadar kateri koli vnos potrebuje razširjene zastavice.

Različica 4: doda stiskanje predpon poti. Namesto shranjevanja celotnih poti vsak vnos shrani število bajtov, ki jih je treba odstraniti s poti prejšnjega vnosa, nato pa novo pripono. To občutno zmanjša velikost indeksa pri globoko ugnezdenih drevesih.

Stopnje sporov

Med sporom pri združevanju ima lahko ena pot več vnosov indeksa na različnih stopnjah:

Stopnja Pomen
0 Običajno (brez spora)
1 Osnovna različica (skupni prednik)
2 Naša različica (trenutna veja)
3 Njihova različica (veja, ki se združuje)
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]

Razširitve indeksa

Razširitve so dodane za vnosi in pred kontrolno vsoto. Vsaka razširitev ima 4-bajtni podpis, 4-bajtno velikost in podatke spremenljive dolžine.

Pitmaster ohrani bloke razširitev kot surove bajte ($index->extensions() vrne pare signature in data) ter jih nespremenjene zapiše nazaj, kadar vnosi niso bili spremenjeni. Razširitev ne razlaga ali ustvarja; vsaka sprememba vnosov pa vse razširitve odstrani, kar git sprejme in po potrebi znova zgradi. Razširitve, ki jih uporablja git, so za referenco opisane spodaj.

Razširitev TREE

Predpomni vnaprej izračunane drevesne objekte za imenike. Pospeši git status in git commit, saj prepreči ponovno računanje dreves, kadar se spremeni samo indeks.

Podpis: TREE (0x54524545)

Razširitev REUC

Zabeleži informacije za razveljavitev razrešitve. Ko je spor razrešen, se izvirni vnosi stopenj 1/2/3 premaknejo sem, da jih je mogoče obnoviti z git checkout -m.

Podpis: REUC (0x52455543)

Druge razširitve

git zapisuje tudi:

  • EOIE (konec vnosa indeksa): označuje, kje se vnosi končajo in začnejo razširitve
  • IEOT (tabela odmikov vnosov indeksa): omogoča vzporedno nalaganje indeksa
  • link (razdeljeni indeks): za zelo velike repozitorije, ki uporabljajo razdeljeni indeks

V obliki git so razširitve s podpisom, ki se začne z veliko črko, neobvezne, tiste z malo črko pa obvezne. Pitmaster sprejema obe vrsti brez preverjanja. Razdeljeni indeks (link) ni naložen, zato repozitoriji, ki ga uporabljajo, niso podprti.

Kontrolna vsota

Datoteka indeksa se konča s kontrolno vsoto vseh predhodnih bajtov, izračunano s funkcijo zgoščevanja repozitorija (20 bajtov SHA-1, 32 bajtov SHA-256). Pitmaster jo zapiše ob shranjevanju, pri branju pa je ne preveri.

Index::open() in Index::parse() ob manjkajočem podpisu DIRC ali nepodprti različici sprožita IndexParseException.

Indeks in stanje

Indeks je osrednji del izračunavanja stanja. WorkingTreeStatus primerja:

  1. Drevo HEAD z indeksom: zazna pripravljene spremembe
  2. Indeks z delovnim drevesom: zazna nepripravljene spremembe

Statistična polja (ctime, mtime, dev, ino, size, mode, uid, gid) omogočajo hitra preverjanja »ali se je ta datoteka spremenila?« brez branja vsebine datoteke. Če se statistična polja ujemajo in je bila datoteka nazadnje spremenjena pred začetkom pregleda stanja, se domneva, da je nespremenjena. Drugačna velikost jo takoj označi kot spremenjeno. Sicer Pitmaster prebere datoteko in izračuna njeno zgoščeno vrednost, da preveri, ali se je vsebina dejansko spremenila.

Zastavica »predpostavi, da je veljavno«

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

Ta zastavica pove git, naj med preverjanjem stanja preskoči preverjanje datoteke, tudi če so se statistična polja spremenila (git update-index --assume-unchanged). Pitmaster ohrani bit pri ponovnem zapisovanju vnosov, vendar ga pri izračunu stanja ne upošteva in datoteko vseeno primerja.