Zum Inhalt springen

Status

Pitmaster berechnet den Status des Arbeitsbaums durch den Vergleich dreier Zustände: des Baums des HEAD-Commits, des Index (Staging-Bereichs) und des Arbeitsbaums (der tatsächlichen Dateien auf dem Datenträger). CLI gibt eine Zusammenfassung im Stil von git status aus, statusPorcelainV2() gibt das Porzellanformat v2 von git aus.

Grundlegende Verwendung

PHP
$entries = $repo->status();

foreach ($entries as $entry) {
    echo $entry->shortFormat() . "\n";
}

shortFormat() gibt das Kurzformat von git aus:

Code
M  src/Modified.php          (staged modification)
 M src/WorktreeModified.php  (unstaged modification)
A  src/NewFile.php           (staged new file)
 D src/Deleted.php           (deleted in worktree)
?? untracked.txt             (untracked file)

StatusEntry

Der Status jeder Datei wird durch ein StatusEntry dargestellt:

PHP
use Pitmaster\Status\StatusEntry;

$entry->path;       // File path relative to repo root
$entry->index;      // FileStatus: HEAD-to-index state
$entry->worktree;   // FileStatus: index-to-worktree state
$entry->origPath;   // Original path for renamed entries, otherwise null
$entry->renameScore; // Similarity score for renamed entries, otherwise null
$entry->shortFormat(); // "XY path", "?? path", or "R  old -> new"

FileStatus-Aufzählung

PHP
use Pitmaster\Status\FileStatus;

FileStatus::Added;      // 'A' - new file
FileStatus::Modified;   // 'M' - content changed
FileStatus::Deleted;    // 'D' - file removed
FileStatus::Renamed;    // 'R' - file renamed
FileStatus::Copied;     // 'C' - file copied
FileStatus::Unmerged;   // 'U' - unresolved merge conflict
FileStatus::Untracked;  // '?' - not in index
FileStatus::Ignored;    // '!' - matched by .gitignore
FileStatus::Unmodified; // ' ' - no change

status() meldet keine ignorierten Dateien, daher erscheint Ignored nicht im Ergebnis.

Porcelain-v2-Ausgabe

Für eine maschinenlesbare Statusausgabe, die git status --porcelain=v2 entspricht:

PHP
echo $repo->statusPorcelainV2();

Ausgabe:

Code
1 .M N... 100644 100644 100644 ce013625030ba8dba906f756967f9e9ca394464a ce013625030ba8dba906f756967f9e9ca394464a modified-file.txt
? untracked-file.txt

Getrackte Einträge erscheinen zuerst, danach nicht getrackte. Umbenennungen verwenden 2-Zeilen und Konflikte u-Zeilen. Die # branch-Header von git status --porcelain=v2 --branch werden nicht ausgegeben, und ignorierte Dateien werden nicht aufgelistet.

So wird der Status berechnet

Die Klasse WorkingTreeStatus führt den Drei-Wege-Vergleich durch:

PHP
use Pitmaster\Status\WorkingTreeStatus;

$status = new WorkingTreeStatus($repo->objectDatabase(), $repo->workDir(), $repo->gitDir());
$entries = $status->compute($repo->index(), $repo->resolve('HEAD'));

Schritt 1: HEAD-Tree-Map erstellen

Den Tree des HEAD-Commits zu einer Map aus path => blob hash abflachen. Diese bildet den zuletzt committeten Zustand ab.

Schritt 2: HEAD mit dem Index vergleichen

Für jede Datei im HEAD-Tree und im Index:

  • In HEAD, aber nicht im Index: Deleted in der Index-Spalte
  • Im Index, aber nicht in HEAD: Added in der Index-Spalte
  • In beiden, aber mit unterschiedlichem Hash: Modified in der Index-Spalte
  • In beiden mit demselben Hash: Unmodified in der Index-Spalte

Schritt 3: Index mit Arbeitsbaum vergleichen

Für jede Datei im Index und im Arbeitsbaum:

  • Im Index, aber nicht auf dem Datenträger: Deleted in der Arbeitsbaum-Spalte
  • In beiden, aber mit unterschiedlichem Inhalt: Modified in der Arbeitsbaum-Spalte
  • In beiden mit übereinstimmendem Inhalt: Unmodified in der Arbeitsbaum-Spalte

Schritt 4: Nicht versionierte Dateien erkennen

Durchsuche das Arbeitsverzeichnis, überspringe .git/ und ignorierte Pfade und melde Dateien, die nicht im Index stehen, in beiden Spalten als Untracked.

Unterstützung für .gitignore

Pitmaster verarbeitet .gitignore-Dateien, um zu bestimmen, welche nicht versionierten Dateien als ignoriert oder nicht versioniert gemeldet werden sollen.

PHP
use Pitmaster\Status\GitIgnore;

Die Klasse GitIgnore verarbeitet gitignore-Muster aus:

  • .gitignore im Repository-Stammverzeichnis
  • .gitignore in Unterverzeichnissen
  • .git/info/exclude

Unterstützte Mustersyntax:

  • Glob-Muster (*.log, build/)
  • Negation (!important.log)
  • Nur für Verzeichnisse geltende Muster (abschließendes /)
  • Führendes / für auf das Stammverzeichnis bezogene Muster
  • ** für rekursive Übereinstimmungen

Statuseinträge kategorisieren

Ein gängiges Muster zur Anzeige von UI:

PHP
$staged = [];
$unstaged = [];
$untracked = [];

foreach ($repo->status() as $entry) {
    if ($entry->index === FileStatus::Untracked) {
        $untracked[] = $entry;
    } elseif ($entry->index !== FileStatus::Unmodified) {
        $staged[] = $entry;
    }

    if ($entry->worktree !== FileStatus::Unmodified
        && $entry->index !== FileStatus::Untracked
    ) {
        $unstaged[] = $entry;
    }
}

Verwendung von CLI

Shell
./vendor/bin/pitmaster status

Ausgabe:

Code
On branch main

Changes to be committed:
	new file:   src/Feature.php

Changes not staged for commit:
	modified:   src/Existing.php

Untracked files:
	notes.txt

Fsmonitor

Pitmaster enthält eine Hilfsfunktion für das fsmonitor-Protokoll von git:

PHP
use Pitmaster\Status\Fsmonitor;

Die Klasse Fsmonitor kann den Hook core.fsmonitor abfragen (und greift ersatzweise auf einen Scan der Änderungszeiten zurück), um festzustellen, welche Dateien sich seit einem Token geändert haben. Bei Handles, die mit ['processes' => false] geöffnet wurden, wird die Funktion deaktiviert. status() ruft sie derzeit nicht auf, sondern vergleicht stat-Daten und Inhalte direkt.