
# Erste Schritte

## Installation

Installiere Pitmaster mit Composer:

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

## Voraussetzungen

- **PHP 8.2+** mit readonly-Klassen, Enums und Konstruktor-Promotion
- **ext-zlib** für die Komprimierung und Dekomprimierung von Objekten (bei den meisten Installationen integriert)
- **ext-json** für Statusdateien von Operationen und API-Nutzdaten von Git LFS
- **ext-mbstring**, deklariert in `composer.json`, weshalb Composer es bei der Installation verlangt
- **ext-ctype** für die Hash-Validierung (in den meisten PHP-Builds aktiviert, aber nicht in `composer.json` deklariert)

Für grundlegende Repository-Operationen sind weder das `git`-Binary noch FFI oder externe Hilfsprogramme erforderlich. Optionale Funktionen haben zusätzliche Laufzeitanforderungen: Hooks werden mit `proc_open()` ausgeführt, und der SSH-Transport verwendet `ext-ssh2`, wenn es geladen ist, andernfalls startet er das System-`ssh`-Binary über `proc_open()`.

## Ein vorhandenes Repository öffnen

```php
use Pitmaster\Pitmaster;

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

Damit wird das Repository am angegebenen Pfad geöffnet. Pitmaster ermittelt das `.git`-Verzeichnis (oder löst bei verknüpften Worktrees eine `.git`-Datei auf) und initialisiert die Objektdatenbank, die Referenzdatenbank und die Konfiguration.

`open()`, `init()` und `clone()` akzeptieren als letztes Argument ein Options-Array:

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

Hooks werden standardmäßig ausgeführt. `Pitmaster::processFreeOptions()` gibt `['processes' => false, 'hooks' => false]` zurück; lokale Lese- und Schreibvorgänge funktionieren mit diesem Handle weiterhin.

## Prüfen, ob ein Pfad ein Repository ist

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

## Ein neues Repository initialisieren

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

Dadurch wird die `.git`-Verzeichnisstruktur mit Objekten, Referenzen, HEAD (der auf `refs/heads/main` verweist) und einer Standardkonfiguration erstellt.

Um ein Repository mit SHA-256 anzulegen, übergib das Objektformat als zweites Argument:

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

Objekt-IDs in diesem Repository bestehen aus 64 Hex-Zeichen, und die Konfiguration speichert `extensions.objectformat = sha256`. Bei späterem Öffnen übernehmen Repositorys das Format aus diesem Konfigurationseintrag.

## Den HEAD-Commit lesen

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

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

Die Methode `head()` löst HEAD auf (einschließlich symbolischer Referenzen) und gibt ein `Commit`-Objekt zurück.

## Branches und Tags auflisten

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

## Commit-Historie durchlaufen

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

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

Du kannst auch bei einem bestimmten Commit beginnen:

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

## Status des Arbeitsverzeichnisses prüfen

```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";
    }
}
```

## Dateien zum Commit vormerken und committen

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

Name und E-Mail-Adresse des Autors werden in dieser Reihenfolge ermittelt: aus den Umgebungsvariablen `PITMASTER_AUTHOR_NAME` / `PITMASTER_AUTHOR_EMAIL`, den Umgebungsvariablen `GIT_AUTHOR_NAME` / `GIT_AUTHOR_EMAIL`, den Konstanten `PITMASTER_AUTHOR_NAME` / `PITMASTER_AUTHOR_EMAIL`, der Repository-Konfiguration (`.git/config` sowie `user.name` und `user.email`) und schließlich `Pitmaster <pitmaster@localhost>`. Gelesen wird nur die Repository-Konfigurationsdatei (und die darin eingebundenen Dateien), nicht `~/.gitconfig`. Der Committer wird auf dieselbe Weise anhand der Namen unter `*_COMMITTER_*` ermittelt; falls dort keine Werte vorhanden sind, werden die Autorenkonstanten verwendet.

## Diffs berechnen

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

## Ein Remote-Repository klonen

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

Dabei werden Referenzen ermittelt, die Pack-Datei abgerufen, Remote-Tracking-Branches eingerichtet und der Standardbranch ausgecheckt. HTTP(S)-URLs verwenden Smart-HTTP und greifen bei Bedarf auf Dumb-HTTP zurück; für SSH-URLs wird der SSH-Transport verwendet. Für einen flachen Klon übergib die Tiefe als drittes Argument: `Pitmaster::clone($url, $path, 1)`.

## Ein beliebiges Objekt anhand seines Hashes lesen

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

## Konfiguration

Pitmaster berücksichtigt die `.git/config` des Repositorys für Autoreninformationen und Remote-URLs. Du kannst mit den Konstanten PHP auch globale Standardwerte festlegen. Definiere sie, bevor Pitmaster ausgeführt wird:

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

| Konstante | Standardwert | Wirkung |
|----------|---------|--------|
| `PITMASTER_AUTHOR_NAME`, `PITMASTER_AUTHOR_EMAIL` | none | Identität des Autors (siehe Reihenfolge oben) |
| `PITMASTER_COMMITTER_NAME`, `PITMASTER_COMMITTER_EMAIL` | Autorenwerte | Identität des Committers |
| `PITMASTER_HTTP_TIMEOUT` | `30` | Timeout für Smart-HTTP in Sekunden (Ganzzahl) |
| `PITMASTER_MAX_DELTA_CHAIN` | `50` | Maximale Delta-Kettentiefe beim Lesen von Packs (Ganzzahl) |
| `PITMASTER_OBJECT_CACHE_ENTRIES` | `1024` | Objekte im In-Memory-Objektcache |
| `PITMASTER_OBJECT_CACHE_BYTES` | `16M` | Byte-Budget des Objekt-Caches |
| `PITMASTER_PACK_RESOLVED_CACHE_ENTRIES` | `4096` | Aufgelöste Delta-Objekte, die pro Pack im Cache gehalten werden |
| `PITMASTER_PACK_RESOLVED_CACHE_BYTES` | `32M` | Byte-Budget dieses Pack-Caches |
| `PITMASTER_MAX_PACK_MEMORY` | none | Älterer Name für das Byte-Budget des Pack-Caches, wird nur verwendet, wenn `PITMASTER_PACK_RESOLVED_CACHE_BYTES` nicht definiert ist |

Byte-Werte können als Ganzzahl oder als Zeichenfolge mit dem Suffix `k`, `m` oder `g` angegeben werden (`'256M'`). Ungültige Werte werden durch den Standardwert ersetzt.

Umgebungsvariablen überschreiben die Identitätskonstanten: `PITMASTER_AUTHOR_NAME`, `PITMASTER_AUTHOR_EMAIL`, `PITMASTER_AUTHOR_DATE`, die entsprechenden `PITMASTER_COMMITTER_*`-Variablen sowie die git-eigenen Variablen `GIT_AUTHOR_*` und `GIT_COMMITTER_*`. Der SSH-Transport liest die unter [Protokolle](https://pitmaster.inline0.dev/de/docs/network/protocols) beschriebenen Variablen `PITMASTER_SSH_*`.

Für den Hash-Algorithmus gibt es keine Konstante. Das Objektformat wird beim Erstellen des Repositorys gewählt (`Pitmaster::init($path, 'sha256')` oder `init --object-format=sha256` auf dem CLI) und anschließend aus der Repository-Konfiguration gelesen.
