Indekso formatas
Indekso failas (.git/index) yra paruošimo sritis. Jame įrašomi failai, kurie bus įtraukti į kitą commit, ir metaduomenys, padedantys efektyviai apskaičiuoti būseną. Pitmaster skaito 2, 3 ir 4 versijų indeksus, o rašo 2 ir 3 versijų indeksus. Įrašius indeksą, kuris buvo nuskaitytas kaip 4 versija, sukuriamas Git neskaitomas failas (#15), todėl prieš rašydami per Pitmaster tokias saugyklas konvertuokite naudodami git update-index --index-version 2.
Indekso skaitymas
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');
Jei failo nėra, Index::open() grąžina tuščią indeksą. entries() grąžina tik 0 etapo įrašus; allEntries() įtraukia konfliktų etapus, o paths() pateikia sekamus kelius.
IndexEntry
Kiekvienas indekso įrašas yra tik skaitymui skirtas reikšmės objektas:
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
Įrašų kūrimas
// 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);
Indekso keitimas
// 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() ir removeEntries() vienu veiksmu apdoroja kelis įrašus ar kelius. Pakeitus įrašus, išsaugoti plėtiniai pašalinami (žr. toliau).
Indekso įrašymas
use Pitmaster\Index\IndexWriter;
IndexWriter::write($index, '/path/to/.git/index');
Arba per saugyklą (kuri tai atlieka automatiškai):
$repo->add('src/File.php'); // Reads file, creates blob, updates index, writes
$repo->remove('--cached', 'old-file.txt'); // Removes from index only, writes
Dvejetainis formatas
Antraštė
Signature: DIRC (4 bytes, ASCII)
Version: 4 bytes, big-endian (2, 3, or 4)
Entry count: 4 bytes, big-endian
Įrašo formatas (v2)
Kiekvieną įrašą sudaro:
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
Vėliavų laukas:
- Bitas 15: galiojimo laikoma vėliava
- Bitai 13-12: suliejimo etapas (0-3)
- Bitai 11-0: kelio pavadinimo ilgis arba 0xFFF, jei kelias yra 4095 baitų ar ilgesnis (tuomet skaitytuvas ieško NUL)
Versijų skirtumai
2 versija: aukščiau aprašytas bazinis formatas. Dažniausiai naudojama.
3 versija: pridedamos išplėstinės vėliavos (2 papildomi baitai po įprastų vėliavų). Palaikomi bitai skip-worktree ir intent-to-add. Naudojama, kai kuriam nors įrašui reikia išplėstinių vėliavų.
4 versija: pridedamas kelių prefiksų glaudinimas. Užuot saugojus visus kelius, kiekviename įraše saugoma, kiek baitų pašalinti iš ankstesnio įrašo kelio, o tada – nauja priesaga. Gerokai sumažina indekso dydį, kai medžiai giliai įdėti.
Konfliktų etapai
Kilęs suliejimo konfliktas gali sukurti vienam keliui kelis skirtingų etapų indekso įrašus:
| Etapas | Reikšmė |
|---|---|
| 0 | Įprastas (konflikto nėra) |
| 1 | Bazinė versija (bendras protėvis) |
| 2 | Mūsų (dabartinė šaka) |
| 3 | Jų (suliejama šaka) |
// 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]
Indekso plėtiniai
Plėtiniai pridedami po įrašų, prieš kontrolinę sumą. Kiekvieną plėtinį sudaro 4 baitų parašas, 4 baitų dydis ir kintamo ilgio duomenys.
Pitmaster plėtinių blokus saugo kaip neapdorotus baitus ($index->extensions() grąžina signature ir data poras) ir, jei įrašai nepakeisti, juos įrašo atgal nepakeistus. Jis neinterpretuoja ir negeneruoja jokių plėtinių, o pakeitus įrašus visi jie pašalinami; git tai priima ir prireikus atkuria. Toliau pateikiamas naudojamų plėtinių git aprašas.
TREE plėtinys
Katalogams talpykloje saugomi iš anksto apskaičiuoti medžių objektai. Paspartina git status ir git commit, nes išvengiama pakartotinio medžio skaičiavimo, kai pasikeitė tik indeksas.
Parašas: TREE (0x54524545)
REUC plėtinys
Įrašo atšaukimo informaciją. Išsprendus konfliktą, pradiniai 1/2/3 etapo įrašai perkeliami čia, kad juos būtų galima atkurti naudojant git checkout -m.
Parašas: REUC (0x52455543)
Kiti plėtiniai
git taip pat įrašo:
EOIE(indekso įrašo pabaiga): nurodo, kur baigiasi įrašai ir prasideda plėtiniaiIEOT(indekso įrašų poslinkių lentelė): leidžia lygiagrečiai įkelti indeksąlink(padalytas indeksas): labai didelėms saugykloms, naudojančioms padalytą indeksą
git formate plėtiniai, kurių parašas prasideda didžiąja raide, yra pasirenkami, o prasidedantys mažąja – privalomi. Pitmaster priima abiejų rūšių plėtinius jų netikrindama. Padalytas indeksas (link) neįkeliamas, todėl saugyklos, kuriose jis naudojamas, nepalaikomos.
Kontrolinė suma
Indekso failo pabaigoje įrašoma visų ankstesnių baitų kontrolinė suma, apskaičiuota pagal saugyklos maišos algoritmą (20 baitų SHA-1, 32 baitai SHA-256). Pitmaster ją įrašo išsaugant, bet skaitydama netikrina.
Index::open() ir Index::parse() iškelia IndexParseException, jei trūksta DIRC parašo arba nurodyta nepalaikoma versija.
Indeksas ir būsena
Indeksas yra pagrindinis būsenos apskaičiavimo elementas. WorkingTreeStatus lygina:
- HEAD medį su indeksu: aptinka paruoštus pakeitimus
- Indeksą su darbiniu medžiu: aptinka neparuoštus pakeitimus
Statistikos laukai (ctime, mtime, dev, ino, size, mode, uid, gid) leidžia greitai patikrinti, ar failas pasikeitė, neskaitant jo turinio. Jei statistikos laukai sutampa, o failas buvo paskutinį kartą pakeistas prieš pradedant būsenos tikrinimą, laikoma, kad jis nepasikeitė. Jei dydis skiriasi, failas iškart pažymimas kaip pakeistas. Kitu atveju Pitmaster perskaito failą ir apskaičiuoja jo maišą, kad patikrintų, ar turinys iš tikrųjų pasikeitė.
Galiojančio failo žyma
if ($entry->assumeValid()) {
// Entry has assume-valid set (flags & 0x8000)
}
Ši žyma nurodo git netikrinti failo būsenos tikrinimo metu, net jei statistikos laukai pasikeitė (git update-index --assume-unchanged). Pitmaster išsaugo šį bitą perrašydama įrašus, bet būsenos tikrinimo metu į jį neatsižvelgia ir vis tiek palygina failą.