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); 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
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:
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
// 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
// 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
use Pitmaster\Index\IndexWriter;
IndexWriter::write($index, '/path/to/.git/index');
Vagy a tárolón keresztül (amely ezt automatikusan kezeli):
$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:
- 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) |
// 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étIEOT(indexbejegyzés-eltolástábla): lehetővé teszi az index párhuzamos betöltésétlink(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:
- HEAD fa és index: az előkészített módosítások észlelése
- 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ő
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.