
# Guida introduttiva

## Installazione

Installate Pitmaster tramite Composer:

```bash
composer require pitmaster/pitmaster
```

## Requisiti

- **PHP 8.2+** con classi readonly, enum e promozione del costruttore
- **ext-zlib** per comprimere e decomprimere gli oggetti (integrato nella maggior parte delle installazioni)
- **ext-json** per i file di stato delle operazioni e i payload Git LFS API
- **ext-mbstring**, dichiarato in `composer.json`, quindi Composer lo richiede al momento dell'installazione
- **ext-ctype** per la convalida degli hash (abilitato nella maggior parte delle build PHP, ma non dichiarato in `composer.json`)

Le operazioni fondamentali sui repository non richiedono il binario `git`, FFI o helper esterni. Le funzionalità opzionali hanno requisiti di runtime aggiuntivi: l'esecuzione degli hook usa `proc_open()`, mentre il trasporto SSH usa `ext-ssh2` se caricato; altrimenti avvia il binario `ssh` di sistema tramite `proc_open()`.

## Aprire un repository esistente

```php
use Pitmaster\Pitmaster;

$repo = Pitmaster::open('/path/to/project');
```

Apre il repository nel percorso indicato. Pitmaster individua la directory `.git` (o risolve un file `.git` per i worktree collegati) e inizializza il database degli oggetti, il database dei riferimenti e la configurazione.

`open()`, `init()` e `clone()` accettano un array di opzioni come ultimo argomento:

```php
// Do not run .git/hooks scripts for this handle
$repo = Pitmaster::open('/path/to/project', ['hooks' => false]);

// Do not start any process: no hooks, no fsmonitor hook, no clone/fetch/push, no SSH
$repo = Pitmaster::open('/path/to/project', Pitmaster::processFreeOptions());
```

Gli hook vengono eseguiti per impostazione predefinita. `Pitmaster::processFreeOptions()` restituisce `['processes' => false, 'hooks' => false]`; le letture e le scritture locali continuano a funzionare con un handle di questo tipo.

## Verificare se un percorso è un repository

```php
if (Pitmaster::isRepository('/path/to/project')) {
    $repo = Pitmaster::open('/path/to/project');
}
```

## Inizializzare un nuovo repository

```php
$repo = Pitmaster::init('/path/to/new-project');
```

Crea la struttura di directory `.git` con oggetti, riferimenti, HEAD (che punta a `refs/heads/main`) e una configurazione predefinita.

Per creare un repository SHA-256, passate il formato degli oggetti come secondo argomento:

```php
$repo = Pitmaster::init('/path/to/new-project', 'sha256');
```

Gli ID oggetto in quel repository sono stringhe esadecimali di 64 caratteri e la configurazione registra `extensions.objectformat = sha256`. I repository aperti in seguito ricavano il formato da questa voce di configurazione.

## Leggere il commit HEAD

```php
$head = $repo->head();

echo "Commit: {$head->id->hex}\n";
echo "Author: {$head->author}\n";
echo "Message: {$head->message}\n";
```

Il metodo `head()` risolve HEAD (seguendo i riferimenti simbolici) e restituisce un oggetto `Commit`.

## Elencare rami e tag

```php
// All branch names
$branches = $repo->branches();
// ['main', 'feature/login', 'bugfix/typo']

// Current branch name (null if detached)
$current = $repo->branch();
// 'main'

// All tag names
$tags = $repo->tags();
// ['v1.0.0', 'v1.1.0']
```

## Esplorare la cronologia dei commit

```php
// Last 20 commits from HEAD
$commits = $repo->log(20);

foreach ($commits as $commit) {
    echo substr($commit->id->hex, 0, 7) . " {$commit->message}\n";
}
```

È possibile anche partire da un commit specifico:

```php
$from = $repo->resolve('feature/login');
$commits = $repo->log(10, $from);
```

## Controllare lo stato dell'albero di lavoro

```php
use Pitmaster\Status\FileStatus;

$entries = $repo->status();

foreach ($entries as $entry) {
    if ($entry->index === FileStatus::Untracked) {
        echo "?? {$entry->path}\n";
    } elseif ($entry->index === FileStatus::Modified) {
        echo "M  {$entry->path}\n";
    } elseif ($entry->worktree === FileStatus::Modified) {
        echo " M {$entry->path}\n";
    }
}
```

## Aggiungere file all'area di staging e creare un commit

```php
// Stage specific files
$repo->add('src/Feature.php', 'tests/FeatureTest.php');

// Create a commit
$commitId = $repo->commit('Add new feature with tests');

echo "Created commit: {$commitId->hex}\n";
```

Il nome e l'indirizzo email dell'autore vengono risolti in quest'ordine: le variabili d'ambiente `PITMASTER_AUTHOR_NAME` / `PITMASTER_AUTHOR_EMAIL`, le variabili d'ambiente `GIT_AUTHOR_NAME` / `GIT_AUTHOR_EMAIL`, le costanti `PITMASTER_AUTHOR_NAME` / `PITMASTER_AUTHOR_EMAIL`, la `.git/config` del repository (`user.name` e `user.email`) e infine `Pitmaster <pitmaster@localhost>`. Viene letto solo il file di configurazione del repository (e i file inclusi), non `~/.gitconfig`. Il committer viene risolto nello stesso modo usando i nomi `*_COMMITTER_*` e, in mancanza, le costanti dell'autore.

## Calcolare le differenze

```php
// Unstaged changes (worktree vs index)
$diffs = $repo->diff();

foreach ($diffs as $diff) {
    echo $diff->format(); // Unified diff output
}

// Staged changes (index vs HEAD)
$staged = $repo->diffStaged();
```

## Clonare un repository remoto

```php
$repo = Pitmaster::clone('https://github.com/user/repo.git', '/path/to/destination');
```

Individua i riferimenti, scarica il file pack, configura i rami di tracciamento remoto ed esegue il checkout del ramo predefinito. Gli URL HTTP(S) usano HTTP intelligente e ripiegano su HTTP semplice; gli URL SSH usano il trasporto SSH. Passate una profondità come terzo argomento per un clone superficiale: `Pitmaster::clone($url, $path, 1)`.

## Leggere qualsiasi oggetto tramite hash

```php
$object = $repo->readObject($fullHash); // full 40-character (or 64 for SHA-256) hex hash

if ($object instanceof \Pitmaster\Object\Blob) {
    echo $object->content;
} elseif ($object instanceof \Pitmaster\Object\Commit) {
    echo $object->message;
}
```

## Configurazione

Pitmaster rispetta la `.git/config` del repository per le informazioni sull'autore e gli URL remoti. È possibile anche impostare valori predefiniti globali con le costanti PHP, definite prima dell'esecuzione di Pitmaster:

```php
define('PITMASTER_AUTHOR_NAME', 'Your Name');
define('PITMASTER_AUTHOR_EMAIL', 'you@example.com');
define('PITMASTER_HTTP_TIMEOUT', 60);        // Seconds
define('PITMASTER_MAX_DELTA_CHAIN', 50);     // Max delta chain depth
define('PITMASTER_OBJECT_CACHE_BYTES', '64M');
```

| Costante | Predefinito | Effetto |
|----------|---------|--------|
| `PITMASTER_AUTHOR_NAME`, `PITMASTER_AUTHOR_EMAIL` | nessuno | Identità dell'autore (vedere l'ordine sopra) |
| `PITMASTER_COMMITTER_NAME`, `PITMASTER_COMMITTER_EMAIL` | valori dell'autore | Identità del committer |
| `PITMASTER_HTTP_TIMEOUT` | `30` | Timeout per HTTP intelligente, in secondi (intero) |
| `PITMASTER_MAX_DELTA_CHAIN` | `50` | Profondità massima della catena delta durante la lettura dei pack (intero) |
| `PITMASTER_OBJECT_CACHE_ENTRIES` | `1024` | Oggetti conservati nella cache degli oggetti in memoria |
| `PITMASTER_OBJECT_CACHE_BYTES` | `16M` | Limite in byte della cache degli oggetti |
| `PITMASTER_PACK_RESOLVED_CACHE_ENTRIES` | `4096` | Oggetti delta risolti memorizzati nella cache per pack |
| `PITMASTER_PACK_RESOLVED_CACHE_BYTES` | `32M` | Limite in byte di tale cache dei pack |
| `PITMASTER_MAX_PACK_MEMORY` | nessuno | Nome precedente per il limite in byte della cache dei pack, usato solo se `PITMASTER_PACK_RESOLVED_CACHE_BYTES` non è definito |

I valori in byte accettano un intero o una stringa con suffisso `k`, `m` o `g` (`'256M'`). I valori non validi vengono sostituiti con quello predefinito.

Le variabili d'ambiente hanno la precedenza sulle costanti di identità: `PITMASTER_AUTHOR_NAME`, `PITMASTER_AUTHOR_EMAIL`, `PITMASTER_AUTHOR_DATE`, i relativi equivalenti `PITMASTER_COMMITTER_*` e le variabili `GIT_AUTHOR_*` e `GIT_COMMITTER_*` proprie di git. Il trasporto SSH legge le variabili `PITMASTER_SSH_*`, descritte in [Protocolli](https://pitmaster.inline0.dev/it/docs/network/protocols).

Non esiste una costante per l'algoritmo hash. Il formato degli oggetti viene scelto quando si crea il repository (`Pitmaster::init($path, 'sha256')` o `init --object-format=sha256` su CLI) e in seguito viene letto dalla configurazione del repository.
