Μετάβαση στο περιεχόμενο

Μορφή index

Το αρχείο index (.git/index) είναι η περιοχή staging. Καταγράφει τα αρχεία που θα συμπεριληφθούν στο επόμενο commit, μαζί με μεταδεδομένα για αποτελεσματικό υπολογισμό της κατάστασης. Το Pitmaster διαβάζει τις εκδόσεις index 2, 3 και 4 και γράφει τις εκδόσεις 2 και 3. Η εγγραφή index που διαβάστηκε ως έκδοση 4 δημιουργεί αρχείο που δεν μπορεί να διαβάσει το git (#15), γι' αυτό μετατρέψτε τέτοια αποθετήρια με το git update-index --index-version 2 πριν από την εγγραφή μέσω του Pitmaster.

Ανάγνωση του index

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() επιστρέφει κενό index αν το αρχείο δεν υπάρχει. Το entries() επιστρέφει μόνο εγγραφές σταδίου 0· το allEntries() περιλαμβάνει στάδια διενέξεων και το paths() παραθέτει τις παρακολουθούμενες διαδρομές.

IndexEntry

Κάθε εγγραφή στο index είναι ένα αντικείμενο τιμής μόνο για ανάγνωση:

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

Δημιουργία εγγραφών

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

Τροποποίηση του index

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() και removeEntries() δέχονται πολλές εγγραφές ή διαδρομές σε μία διέλευση. Κάθε αλλαγή στις εγγραφές απορρίπτει τις αποθηκευμένες επεκτάσεις (βλ. παρακάτω).

Εγγραφή του index

PHP
use Pitmaster\Index\IndexWriter;

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

Ή μέσω του αποθετηρίου (το οποίο το διαχειρίζεται αυτόματα):

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

Δυαδική μορφή

Κώδικας
Signature:   DIRC (4 bytes, ASCII)
Version:     4 bytes, big-endian (2, 3, or 4)
Entry count: 4 bytes, big-endian

Μορφή εγγραφής (v2)

Κάθε εγγραφή έχει τη μορφή:

Κώδικας
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

Το πεδίο flags:

  • Bit 15: σημαία assume-valid
  • Bits 13-12: στάδιο συγχώνευσης (0-3)
  • Bits 11-0: μήκος ονόματος διαδρομής ή 0xFFF όταν η διαδρομή έχει 4095 byte ή περισσότερα (ο αναγνώστης σαρώνει τότε μέχρι το NUL)

Διαφορές εκδόσεων

Έκδοση 2: η βασική μορφή που περιγράφεται παραπάνω. Η πιο συνηθισμένη.

Έκδοση 3: προσθέτει εκτεταμένες σημαίες (2 επιπλέον byte μετά τις κανονικές σημαίες). Υποστηρίζει τα bit skip-worktree και intent-to-add. Χρησιμοποιείται όταν οποιαδήποτε εγγραφή χρειάζεται εκτεταμένες σημαίες.

Έκδοση 4: προσθέτει συμπίεση προθέματος διαδρομής. Αντί να αποθηκεύεται ολόκληρη η διαδρομή, κάθε εγγραφή αποθηκεύει πόσα byte πρέπει να αφαιρεθούν από τη διαδρομή της προηγούμενης εγγραφής και έπειτα το νέο επίθημα. Μειώνει σημαντικά το μέγεθος του index σε βαθιά ένθετα δέντρα.

Στάδια διένεξης

Κατά τη διάρκεια διένεξης συγχώνευσης, μία διαδρομή μπορεί να έχει πολλές εγγραφές index σε διαφορετικά στάδια:

Στάδιο Σημασία
0 Κανονικό (χωρίς διένεξη)
1 Βασική έκδοση (κοινός πρόγονος)
2 Η δική μας (τρέχων κλάδος)
3 Η δική τους (κλάδος που συγχωνεύεται)
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]

Επεκτάσεις index

Οι επεκτάσεις προστίθενται μετά τις εγγραφές και πριν από το άθροισμα ελέγχου. Κάθε επέκταση έχει υπογραφή 4 byte, μέγεθος 4 byte και δεδομένα μεταβλητού μήκους.

Το Pitmaster διατηρεί τα μπλοκ επεκτάσεων ως ακατέργαστα byte (το $index->extensions() επιστρέφει ζεύγη signature και data) και τα ξαναγράφει χωρίς αλλαγές όταν οι εγγραφές παραμένουν ανέπαφες. Δεν ερμηνεύει ούτε δημιουργεί επεκτάσεις και κάθε αλλαγή στις εγγραφές τις απορρίπτει όλες· το git τις δέχεται και τις αναδημιουργεί όταν χρειάζεται. Οι επεκτάσεις που χρησιμοποιεί το git περιγράφονται παρακάτω για αναφορά.

Επέκταση TREE

Αποθηκεύει προσωρινά προϋπολογισμένα αντικείμενα δέντρου για καταλόγους. Επιταχύνει τα git status και git commit αποφεύγοντας τον επανυπολογισμό του δέντρου όταν έχει αλλάξει μόνο το index.

Υπογραφή: TREE (0x54524545)

Επέκταση REUC

Καταγράφει πληροφορίες αναίρεσης επίλυσης. Αφού επιλυθεί μια διένεξη, οι αρχικές εγγραφές σταδίων 1/2/3 μεταφέρονται εδώ, ώστε να μπορούν να επαναφερθούν με το git checkout -m.

Υπογραφή: REUC (0x52455543)

Άλλες επεκτάσεις

Το git γράφει επίσης:

  • EOIE (τέλος εγγραφών index): ορίζει πού τελειώνουν οι εγγραφές και πού αρχίζουν οι επεκτάσεις
  • IEOT (πίνακας μετατοπίσεων εγγραφών index): επιτρέπει την παράλληλη φόρτωση του index
  • link (διαιρεμένο index): για πολύ μεγάλα αποθετήρια που χρησιμοποιούν split index

Στη μορφή του git, οι επεκτάσεις των οποίων η υπογραφή αρχίζει με κεφαλαίο γράμμα είναι προαιρετικές, ενώ όσες αρχίζουν με πεζό είναι υποχρεωτικές. Το Pitmaster δέχεται και τους δύο τύπους χωρίς έλεγχο. Δεν φορτώνεται διαιρεμένο index (link), επομένως δεν υποστηρίζονται αποθετήρια που το χρησιμοποιούν.

Άθροισμα ελέγχου

Το αρχείο index τελειώνει με άθροισμα ελέγχου όλων των προηγούμενων byte, χρησιμοποιώντας τον αλγόριθμο κατακερματισμού του αποθετηρίου (20 byte SHA-1, 32 byte SHA-256). Το Pitmaster το γράφει κατά την αποθήκευση, αλλά δεν το επαληθεύει κατά την ανάγνωση.

Τα Index::open() και Index::parse() προκαλούν IndexParseException αν λείπει η υπογραφή DIRC ή αν η έκδοση δεν υποστηρίζεται.

Index και κατάσταση

Το index είναι κεντρικό στον υπολογισμό της κατάστασης. Το WorkingTreeStatus συγκρίνει:

  1. δέντρο HEAD με index: εντοπίζει αλλαγές που έχουν προστεθεί στο staging
  2. index με δέντρο εργασίας: εντοπίζει αλλαγές που δεν έχουν προστεθεί στο staging

Τα πεδία stat (ctime, mtime, dev, ino, size, mode, uid, gid) επιτρέπουν γρήγορους ελέγχους «άλλαξε αυτό το αρχείο;» χωρίς ανάγνωση του περιεχομένου του. Αν τα πεδία stat ταιριάζουν και το αρχείο τροποποιήθηκε τελευταία φορά πριν αρχίσει η σάρωση κατάστασης, το αρχείο θεωρείται αμετάβλητο. Διαφορετικό μέγεθος το χαρακτηρίζει αμέσως ως τροποποιημένο. Διαφορετικά, το Pitmaster διαβάζει το αρχείο και υπολογίζει τον κατακερματισμό του για να ελέγξει αν άλλαξε πράγματι το περιεχόμενο.

Σημαία assume-valid

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

Αυτή η σημαία λέει στο git να παραλείψει τον έλεγχο του αρχείου κατά την εμφάνιση της κατάστασης, ακόμη κι αν έχουν αλλάξει τα πεδία stat (git update-index --assume-unchanged). Το Pitmaster διατηρεί το bit όταν ξαναγράφει εγγραφές, αλλά η εμφάνιση κατάστασής του δεν το λαμβάνει υπόψη και εξακολουθεί να συγκρίνει το αρχείο.