Pular para o conteúdo

Status

Pitmaster calcula o status da árvore de trabalho comparando três estados: a árvore do commit HEAD, o índice (área de preparação) e a árvore de trabalho (arquivos reais no disco). CLI exibe um resumo no estilo git status, e statusPorcelainV2() exibe o formato Porcelain v2 de git.

Uso básico

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

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

shortFormat() exibe o formato resumido de git:

Código
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

O status de cada arquivo é representado por um StatusEntry:

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"

Enum FileStatus

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() não informa arquivos ignorados, portanto Ignored não aparece no resultado.

Saída Porcelain v2

Para obter uma saída de status legível por máquina que corresponda a git status --porcelain=v2:

PHP
echo $repo->statusPorcelainV2();

Saída:

Código
1 .M N... 100644 100644 100644 ce013625030ba8dba906f756967f9e9ca394464a ce013625030ba8dba906f756967f9e9ca394464a modified-file.txt
? untracked-file.txt

As entradas rastreadas aparecem primeiro, seguidas pelas não rastreadas. Renomeações usam linhas 2 e conflitos usam linhas u. Os cabeçalhos # branch de git status --porcelain=v2 --branch não são exibidos, e arquivos ignorados não são listados.

Como o status é calculado

A classe WorkingTreeStatus realiza a comparação de três vias:

PHP
use Pitmaster\Status\WorkingTreeStatus;

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

Etapa 1: Criar o mapa da árvore HEAD

Achate a árvore do commit HEAD em um mapa de path => blob hash. Isso representa o último estado commitado.

Etapa 2: Comparar o HEAD com o índice

Para cada arquivo na árvore HEAD e no índice:

  • No HEAD, mas não no índice: Deleted na coluna do índice
  • No índice, mas não no HEAD: Added na coluna do índice
  • Em ambos, mas com hashes diferentes: Modified na coluna do índice
  • Em ambos, com o mesmo hash: Unmodified na coluna do índice

Etapa 3: Comparar o índice com a árvore de trabalho

Para cada arquivo no índice e na árvore de trabalho:

  • No índice, mas não no disco: Deleted na coluna da árvore de trabalho
  • Em ambos, mas com conteúdo diferente: Modified na coluna da árvore de trabalho
  • Em ambos, com conteúdo correspondente: Unmodified na coluna da árvore de trabalho

Etapa 4: Detectar arquivos não rastreados

Percorra o diretório da árvore de trabalho, ignore .git/ e os caminhos ignorados e informe os arquivos ausentes do índice como Untracked em ambas as colunas.

Compatibilidade com .gitignore

Pitmaster analisa arquivos .gitignore para determinar quais arquivos não rastreados devem ser informados como ignorados ou não rastreados.

PHP
use Pitmaster\Status\GitIgnore;

A classe GitIgnore analisa padrões gitignore em:

  • .gitignore na raiz do repositório
  • .gitignore nos subdiretórios
  • .git/info/exclude

Sintaxe de padrões compatível:

  • Padrões glob (*.log, build/)
  • Negação (!important.log)
  • Padrões que correspondem apenas a diretórios (/ final)
  • / inicial para padrões relativos à raiz
  • ** para correspondência recursiva

Categorização das entradas de status

Um padrão comum para exibir 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;
    }
}

Uso de CLI

Shell
./vendor/bin/pitmaster status

Saída:

Código
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 inclui um auxiliar para o protocolo fsmonitor de git:

PHP
use Pitmaster\Status\Fsmonitor;

A classe Fsmonitor pode consultar o hook core.fsmonitor (recorrendo a uma verificação das datas de modificação caso necessário) para descobrir quais arquivos mudaram desde um token. Ela se desativa em handles abertos com ['processes' => false]. No momento, status() não o chama; compara diretamente os dados de stat e o conteúdo.