
# État

Pitmaster calcule l’état de l’arbre de travail en comparant trois états : l’arbre du commit HEAD, l’index (zone de préparation) et l’arbre de travail (fichiers présents sur le disque). CLI en affiche un résumé au format `git status`, et `statusPorcelainV2()` affiche le format porcelain v2 de git.

## Utilisation de base

```php
$entries = $repo->status();

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

`shortFormat()` affiche le format court de git :

```
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

L’état de chaque fichier est représenté par un `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"
```

## Énumération 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()` ne signale pas les fichiers ignorés ; `Ignored` n’apparaît donc pas dans son résultat.

## Sortie porcelain v2

Pour obtenir une sortie d’état lisible par machine correspondant à `git status --porcelain=v2` :

```php
echo $repo->statusPorcelainV2();
```

Sortie :

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

Les entrées suivies sont affichées en premier, puis les entrées non suivies. Les renommages utilisent des lignes `2` et les conflits, des lignes `u`. Les en-têtes `# branch` de `git status --porcelain=v2 --branch` ne sont pas affichés et les fichiers ignorés ne sont pas répertoriés.

## Calcul de l’état

La classe `WorkingTreeStatus` effectue la comparaison en trois étapes :

```php
use Pitmaster\Status\WorkingTreeStatus;

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

### Étape 1 : créer la carte de l’arbre HEAD

Aplatit l’arbre du commit HEAD en une carte de `path => blob hash`. Elle représente le dernier état validé.

### Étape 2 : comparer HEAD à l’index

Pour chaque fichier de l’arbre HEAD et de l’index :
- Dans HEAD, mais pas dans l’index : `Deleted` dans la colonne de l’index
- Dans l’index, mais pas dans HEAD : `Added` dans la colonne de l’index
- Dans les deux, mais avec un hachage différent : `Modified` dans la colonne de l’index
- Dans les deux, avec le même hachage : `Unmodified` dans la colonne de l’index

### Étape 3 : comparer l’index à l’arbre de travail

Pour chaque fichier de l’index et de l’arbre de travail :
- Dans l’index, mais absent du disque : `Deleted` dans la colonne de l’arbre de travail
- Dans les deux, mais avec un contenu différent : `Modified` dans la colonne de l’arbre de travail
- Dans les deux, avec un contenu identique : `Unmodified` dans la colonne de l’arbre de travail

### Étape 4 : détecter les fichiers non suivis

Parcourt le répertoire de l’arbre de travail, ignore `.git/` et les chemins ignorés, puis signale comme `Untracked` dans les deux colonnes les fichiers absents de l’index.

## Prise en charge de .gitignore

Pitmaster analyse les fichiers `.gitignore` pour déterminer quels fichiers non suivis doivent être signalés comme ignorés ou non suivis.

```php
use Pitmaster\Status\GitIgnore;
```

La classe `GitIgnore` analyse les motifs gitignore provenant de :
- `.gitignore` à la racine du dépôt
- `.gitignore` dans les sous-répertoires
- `.git/info/exclude`

Syntaxe des motifs prise en charge :
- Motifs glob (`*.log`, `build/`)
- Négation (`!important.log`)
- Motifs réservés aux répertoires (`/` final)
- `/` en début de motif pour le rendre relatif à la racine
- `**` pour une correspondance récursive

## Catégoriser les entrées d’état

Un modèle courant d’affichage de 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;
    }
}
```

## Utilisation de CLI

```bash
./vendor/bin/pitmaster status
```

Sortie :

```
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 inclut un utilitaire pour le protocole fsmonitor de git :

```php
use Pitmaster\Status\Fsmonitor;
```

La classe `Fsmonitor` peut interroger le hook `core.fsmonitor` (et, à défaut, effectuer un balayage des dates de modification) pour déterminer quels fichiers ont changé depuis un jeton. Elle se désactive pour les handles ouverts avec `['processes' => false]`. `status()` ne l’appelle pas pour le moment : il compare directement les données stat et le contenu.
