
# PHP API

## `Pitmaster\Pitmaster`

Třída `Pitmaster\Pitmaster` je statickým vstupním bodem. Poskytuje tovární metody pro otevření, vytvoření a klonování repozitářů a také pomocné funkce pro detekci.

```php
use Pitmaster\Pitmaster;
```

### `open`

```php
public static function open(string $path, array $options = []): Repository
```

Otevřete existující repozitář v `$path`. Cesta by měla vést do kořene pracovního stromu (obsahujícího `.git/`). Podporovány jsou také propojené pracovní stromy (kde je `.git` soubor obsahující `gitdir: <path>`) a holé repozitáře (kde je samotný adresář `$path` `.git`).

`$options` přijímá dvě logické hodnoty, obě jsou ve výchozím nastavení `true`:

- `hooks`: spouští skripty `.git/hooks`. Předejte `false`, chcete-li je pro tuto instanci přeskočit.
- `processes`: povoluje vše, co spouští proces nebo otevírá síťový přenos. Předejte `false`, chcete-li zakázat hooky, hook fsmonitor, clone, fetch, push a přenos procesů SSH. Místní čtení a zápisy zůstanou funkční.

Vyvolá `InvalidArgumentException`, pokud cesta není git repozitář.

```php
$repo = Pitmaster::open('/home/user/project');
$repo = Pitmaster::open('/home/user/project', ['hooks' => false]);
$repo = Pitmaster::open('/home/user/project', Pitmaster::processFreeOptions());
```

### `init`

```php
public static function init(string $path, string $objectFormat = 'sha1', array $options = []): Repository
```

Inicializuje nový repozitář v `$path`. Vytvoří adresářovou strukturu `.git` s položkami `objects/`, `refs/heads/`, `refs/tags/`, `hooks/`, `info/`, `HEAD` (ukazující na `refs/heads/main`) a výchozím `config`.

`$objectFormat` je `'sha1'` nebo `'sha256'`. Holý repozitář SHA-256 získá v konfiguraci `repositoryformatversion = 1` a `extensions.objectformat = sha256`. Jakákoli jiná hodnota vyvolá `InvalidArgumentException`. `$options` přijímá stejné klíče jako `open()`.

Vyvolá `RuntimeException`, pokud na dané cestě repozitář již existuje.

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

### `clone`

```php
public static function clone(string $url, string $path, ?int $depth = null, array $options = []): Repository
```

Naklonuje vzdálený repozitář. Inicializuje nový repozitář, zjistí vzdálené reference, stáhne soubor pack, nastaví vzdálené sledovací větve a vytvoří pracovní strom. URL SSH (`ssh://...` nebo `user@host:path`) používají přenos SSH; ostatní URL používají smart HTTP a při selhání smart výměny přejdou na dumb HTTP. Pro mělký klon předejte `$depth`.

Vyvolá `RuntimeException`, když je `$options['processes']` rovno `false`. Pokud klonování selže a `$path` předtím neexistovalo, částečně vytvořený adresář se odstraní.

```php
$repo = Pitmaster::clone('https://github.com/user/repo.git', '/tmp/repo');
$repo = Pitmaster::clone('https://github.com/user/repo.git', '/tmp/shallow', 1);
$repo = Pitmaster::clone('https://github.com/user/repo.git', '/tmp/repo', null, ['hooks' => false]);
```

### `processFreeOptions`

```php
public static function processFreeOptions(): array
```

Vrátí `['processes' => false, 'hooks' => false]` pro běhová prostředí, která nesmějí spouštět procesy hostitele. Předejte jej do `open()` nebo `init()`.

### `isRepository`

```php
public static function isRepository(string $path): bool
```

Ověří, zda je cesta git repozitář. Vrátí `true` pro běžné repozitáře (adresář `.git/`), propojené pracovní stromy (soubor `.git`) a holé repozitáře (existuje soubor `HEAD`).

```php
if (Pitmaster::isRepository('/path/to/check')) {
    // It's a git repo
}
```

### `isWorktree`

```php
public static function isWorktree(string $path): bool
```

Ověří, zda je cesta propojeným pracovním stromem (nikoli hlavním repozitářem). Vrátí `true` pouze tehdy, když je `.git` soubor obsahující odkaz `gitdir:`.

```php
if (Pitmaster::isWorktree('/path/to/worktree')) {
    // It's a linked worktree
}
```

### `commonGitDir`

```php
public static function commonGitDir(string $path): ?string
```

Vyřeší cestu ke společnému adresáři git z libovolné cesty kontrolní kopie. U běžných repozitářů jde o adresář `.git`. U propojených pracovních stromů jde o sdílený adresář git obsahující objekty, konfiguraci a packed-refs. Pokud cesta není repozitářem, vrátí `null`.

```php
$common = Pitmaster::commonGitDir('/path/to/worktree');
// '/path/to/main-repo/.git'
```

---

## `Pitmaster\Repository`

Třída `Pitmaster\Repository` je hlavním objektem pro všechny operace git. Získejte ji pomocí `Pitmaster::open()`, `Pitmaster::init()` nebo `Pitmaster::clone()`.

```php
use Pitmaster\Repository;
```

### Přístup k cestám

#### `gitDir`

```php
public function gitDir(): string
```

Vrátí adresář git konkrétního pracovního stromu. U běžných repozitářů jde o `.git/`. U propojených pracovních stromů jde o `.git/worktrees/<name>/`.

#### `commonGitDir`

```php
public function commonGitDir(): string
```

Vrátí sdílený adresář git. U běžných repozitářů je stejný jako `gitDir()`. U propojených pracovních stromů jde o adresář `.git/` hlavního repozitáře (kde jsou uloženy objekty, konfigurace a packed-refs).

#### `workDir`

```php
public function workDir(): string
```

Vrátí cestu ke kořeni pracovního stromu.

#### `isLinkedWorktree`

```php
public function isLinkedWorktree(): bool
```

Vrátí `true`, pokud je tato instance repozitáře propojeným pracovním stromem.

#### `isBare`, `hooksEnabled`, `processesEnabled`

```php
public function isBare(): bool
public function hooksEnabled(): bool
public function processesEnabled(): bool
```

Uvede, zda repozitář nemá pracovní strom a které možnosti `hooks` / `processes` jsou pro tuto instanci aktivní. `hooksEnabled()` je `false`, kdykoli jsou procesy zakázány.

---

### Objekty

#### `readObject`

```php
public function readObject(string $hash): GitObject
```

Načte libovolný objekt podle úplného hexadecimálního hashe (40 znaků, nebo 64 v repozitáři SHA-256). Zkrácené hashe nejsou přijímány. Vrátí instanci typu `Blob`, `Tree`, `Commit` nebo `Tag`. Nejprve prohledává volné objekty, poté soubory pack.

Vyvolá `ObjectNotFoundException`, pokud hash nebyl nalezen.

```php
$object = $repo->readObject('a1b2c3d4e5f6...');
```

#### `writeObject`

```php
public function writeObject(GitObject $object): ObjectId
```

Zapíše objekt do úložiště volných objektů. Vrátí vypočtený `ObjectId`.

```php
use Pitmaster\Object\Blob;

$blob = Blob::fromContent('Hello, world!');
$id = $repo->writeObject($blob);
```

#### `catFile`

```php
public function catFile(string $hash): string
```

Vrátí surový obsah objektu, ekvivalent metody `git cat-file -p`.

```php
echo $repo->catFile('a1b2c3d4...');
```

#### `objectExists`

```php
public function objectExists(string $hash): bool
```

Ověří, zda objekt v repozitáři existuje (mezi volnými nebo zabalenými objekty).

#### `listObjects`

```php
public function listObjects(): array
```

Vypíše všechny hashe objektů v repozitáři. Vrátí pole hexadecimálních řetězců.

---

### Reference

#### `head`

```php
public function head(): Commit
```

Vrátí aktuální commit HEAD. Sleduje symbolické reference (HEAD -> refs/heads/main -> hash commitu).

Vyvolá `RuntimeException`, pokud HEAD neukazuje na platný commit (e.g, prázdný repozitář).

#### `branch`

```php
public function branch(?string $name = null): ?string
```

Bez argumentů vrátí název aktuální větve (e.g, `'main'`), nebo `null`, pokud je HEAD odpojený.

S názvem větve jej převede na hash commitu (hexadecimální řetězec), nebo vrátí `null`, pokud větev neexistuje.

```php
$current = $repo->branch();        // 'main'
$hash = $repo->branch('feature');   // 'abc123...' or null
```

#### `branches`

```php
public function branches(): array
```

Vrátí seřazené pole názvů všech větví (bez předpony `refs/heads/`).

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

#### `tags`

```php
public function tags(): array
```

Vrátí seřazené pole názvů všech štítků (bez předpony `refs/tags/`).

#### `resolve`

```php
public function resolve(string $revision): ObjectId
```

Vyřeší výraz revize na `ObjectId`. Podporuje:
- Úplné hexadecimální hashe (40 znaků, nebo 64 pro SHA-256). Zkrácené hashe jako `abc1234` nelze vyřešit.
- `HEAD`
- Názvy větví (`main`, `feature/login`)
- Názvy štítků (`v1.0.0`)
- Úplné cesty referencí (`refs/heads/main`)
- Výrazy revizí (`HEAD~3`, `main^2`)

Vyvolá `RuntimeException`, pokud revizi nelze vyřešit.

```php
$id = $repo->resolve('HEAD~3');
$id = $repo->resolve('v1.0.0');
$id = $repo->resolve('feature/login');
```

#### `allRefs`

```php
public function allRefs(): array
```

Vrátí všechny reference jako asociativní pole názvů referencí a hexadecimálních hashů.

```php
$refs = $repo->allRefs();
// ['refs/heads/main' => 'abc123...', 'refs/tags/v1.0.0' => 'def456...']
```

#### `updateRef`

```php
public function updateRef(string $name, ObjectId $target): void
```

Aktualizuje referenci tak, aby ukazovala na nový cíl.

```php
$repo->updateRef('refs/heads/main', $commitId);
```

#### `createBranch`

```php
public function createBranch(string $name, ?ObjectId $from = null): void
```

Vytvoří novou větev. Pokud je `$from` null, vychází z aktuálního HEAD.

```php
$repo->createBranch('feature/new-thing');
$repo->createBranch('hotfix', $repo->resolve('v1.0.0'));
```

#### `deleteBranch`

```php
public function deleteBranch(string $name): void
```

Smaže větev podle názvu. Vyvolá `RuntimeException`, pokud je větev právě použitá nebo neexistuje. Na rozdíl od `git branch -d` nekontroluje, zda byla větev sloučena.

```php
$repo->deleteBranch('feature/old');
```

#### `createLightweightTag`

```php
public function createLightweightTag(string $name, ?ObjectId $target = null): void
```

Vytvoří odlehčený tag. Pokud je `$target` null, označí přímo aktuální HEAD.

```php
$repo->createLightweightTag('v2.0.0');
$repo->createLightweightTag('hotfix-start', $repo->resolve('main~2'));
```

#### `createTag`

```php
public function createTag(string $name, string $message, ?ObjectId $target = null, ?string $tagger = null): ObjectId
```

Vytvoří anotovaný tag. Pokud je `$target` null, označí aktuální HEAD. Vrátí `ObjectId` objektu tagu.

```php
$tagId = $repo->createTag('v2.0.0', 'Release version 2.0.0');
```

#### `deleteTag`

```php
public function deleteTag(string $name): void
```

Smaže tag podle názvu.

```php
$repo->deleteTag('v1.0.0');
```

#### `packRefs`

```php
public function packRefs(): void
```

Přepište sdílený soubor `packed-refs` z aktuální sady volných odkazů a promažte odpovídající sdílené volné odkazy. U propojených pracovních stromů se zapisuje do společného adresáře git.

```php
$repo->packRefs();
```

#### `defaultBranch`

```php
public function defaultBranch(): string
```

Určí výchozí větev repozitáře. Nejprve zkontroluje symref vzdáleného HEAD, poté lokální HEAD a nakonec použije `main` nebo `master`.

#### `isBranchMerged`

```php
public function isBranchMerged(string $branch, ?string $target = null): bool
```

Zjistí, zda je větev plně sloučena do jiné větve (ve výchozím nastavení do výchozí větve).

```php
if ($repo->isBranchMerged('feature/done')) {
    $repo->deleteBranch('feature/done');
}
```

#### `checkout`

```php
public function checkout(string $target): void
```

Přepne větve nebo odpojí HEAD. Aktualizuje HEAD, index a pracovní strom. `$target` je název větve, tag, úplný hash nebo výraz revize; pokud nejde o větev, HEAD se odpojí.

Vyvolá `RuntimeException`, pokud se v cestě, která se mezi aktuálním a cílovým stromem liší, nachází lokální změna (připravená k potvrzení či nikoli) nebo nesledovaný soubor.

Nepotvrzené změny v ostatních sledovaných souborech se nepřenášejí: index a pracovní strom se znovu vytvoří z cílového stromu, takže úpravy souborů, které jsou na obou stranách totožné, se ztratí, přestože by je git zachoval ([#2](https://github.com/inline0/pitmaster/issues/2)). Nejprve je potvrďte nebo uložte do stash. `merge()`, `cherryPick()`, `revert()`, `rebase()` a metody bisect znovu vytvářejí pracovní strom stejným způsobem.

```php
$repo->checkout('feature/login');
$repo->checkout($repo->resolve('v1.0.0')->hex);  // Detached HEAD
```

---

### Index

#### `index`

```php
public function index(): Index
```

Načte a vrátí aktuální index (přípravnou oblast) z `.git/index`.

#### `add`

```php
public function add(string ...$paths): void
```

Připraví soubory. Načte každý soubor z pracovního stromu, vytvoří objekt blob a aktualizuje index. Každý argument musí být cesta k souboru (nebo symbolickému odkazu) relativní ke kořeni pracovního stromu; adresáře ani vzory se nerozbalují a při chybějícím souboru se vyvolá `RuntimeException`.

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

#### `remove`

```php
public function remove(string ...$paths): void
public function removeCached(string ...$paths): void
```

Odstraní sledované cesty z indexu i pracovního stromu. V seznamu argumentů podporuje `--cached` a `-r` / `--recursive` pro chování odpovídající Git.

```php
$repo->remove('old-file.txt');
$repo->remove('-r', 'src');
$repo->remove('--cached', 'old-file.txt');
$repo->removeCached('old-file.txt');
```

#### `mv`

```php
public function mv(string $source, string $destination): void
```

Přesune/přejmenuje soubor v pracovním stromu i indexu.

```php
$repo->mv('old-name.php', 'new-name.php');
```

---

### Potvrzení

#### `commit`

```php
public function commit(?string $message = null, ?string $author = null): ObjectId
```

Vytvoří commit z aktuálního indexu. Z položek indexu sestaví hierarchii stromu, vytvoří objekt commitu s HEAD jako rodičem (pokud existuje) a aktualizuje HEAD. Vrátí `ObjectId` nového commitu.

`$message` může být `null` pouze tehdy, když se merge, cherry-pick, revert nebo rebase zastaví kvůli konfliktu; v takovém případě se použije připravená zpráva. Jinak prázdná zpráva `null` vyvolá `RuntimeException('Commit message required')`. Commit také vyvolá chybu, pokud index obsahuje nesloučené cesty, pokud je index v repozitáři bez commitů prázdný nebo pokud se strom od HEAD nezměnil.

Parametr `$author` je celý řetězec autora git (`Name <email> timestamp timezone`). Pokud má hodnotu null, určí se z proměnných prostředí, konstant a `.git/config` v pořadí popsaném v [Začínáme](https://pitmaster.inline0.dev/cs/docs/getting-started).

```php
$id = $repo->commit('Fix null pointer bug');
```

#### `show`

```php
public function show(string $revision): array
```

Zobrazí commit-ish a jeho rozdíly oproti prvnímu rodiči. Pokud revize odkazuje na anotovaný tag, návratová hodnota obsahuje také `['tag' => Tag]` a `commit` je dereferencovaný cílový commit.

```php
$result = $repo->show('HEAD');
echo $result['commit']->message;

foreach ($result['diff'] as $diff) {
    echo $diff->format();
}
```

#### `reset`

```php
public function reset(string $revision, string $mode = 'mixed'): void
```

Resetuje HEAD na commit. Režimy:
- `'soft'`: přesune pouze HEAD
- `'mixed'`: přesune HEAD + resetuje index (výchozí)
- `'hard'`: přesune HEAD + resetuje index + resetuje pracovní strom

```php
$repo->reset('HEAD~1', 'soft');
$repo->reset('main', 'hard');
```

#### `restore`

```php
public function restore(string $path, ?string $source = null, bool $staged = false, bool $worktree = false): void
```

Obnoví cestu z indexu nebo zadané zdrojové revize. Pokud není nastaven žádný z příznaků, Pitmaster obnoví pracovní strom z indexu (nebo z `$source`, pokud je zadán). `staged: true` obnoví index z HEAD (nebo z `$source`) a pracovní strom ponechá beze změny; zadáním `staged: true, worktree: true` obnovíte obojí.

```php
$repo->restore('src/File.php');                                        // Worktree from index
$repo->restore('src/File.php', staged: true);                          // Index from HEAD
$repo->restore('src/File.php', 'HEAD~1');                              // Worktree from another commit
$repo->restore('src/File.php', 'HEAD~1', staged: true, worktree: true); // Index + worktree from another commit
```

#### `cherryPick`

```php
public function cherryPick(string $revision): ObjectId
public function cherryPickContinue(): ObjectId
public function cherryPickAbort(): void
```

Použije commit jako nový commit v aktuální větvi a zachová původního autora. Pokud se operace zastaví kvůli konfliktům, vyřešte je, připravte cesty a pak zavolejte `cherryPickContinue()` nebo `cherryPickAbort()`.

```php
$newId = $repo->cherryPick('feature~2');

// After resolving conflicts:
$repo->add('src/File.php');
$repo->cherryPickContinue();
```

#### `revert`

```php
public function revert(string $revision): ObjectId
public function revertContinue(): ObjectId
public function revertAbort(): void
```

Vytvoří commit, který vrátí změny jiného commitu. Pokud se revert zastaví kvůli konfliktům, vyřešte je, připravte cesty a pak zavolejte `revertContinue()` nebo `revertAbort()`.

```php
$revertId = $repo->revert('HEAD~1');

// After resolving conflicts:
$repo->add('src/File.php');
$repo->revertContinue();
```

#### `rebase`

```php
public function rebase(string $onto): array
public function rebaseContinue(): array
public function rebaseAbort(): void
public function rebaseSkip(): array
```

Rebase aktuální větve na jinou revizi. Pitmaster aktuálně podporuje lineární rebase se stavem zastavení Git při konfliktech a také pokračování, zrušení a přeskočení. HEAD musí odkazovat na větev.

`rebase()`, `rebaseContinue()` a `rebaseSkip()` vracejí `['success' => bool, 'commits' => int, 'conflicts' => list<string>]`: zda rebase skončil, kolik commitů bylo použito a cesty s konflikty, pokud se operace zastavila.

```php
$result = $repo->rebase('main');

if (!$result['success']) {
    // Resolve conflicts, then continue or skip/abort.
    $repo->add('src/File.php');
    $repo->rebaseContinue();
}
```

---

### Stav

#### `status`

```php
public function status(): array
```

Vypočítá stav pracovního stromu. Vrátí pole objektů `StatusEntry`, z nichž každý obsahuje:
- `path`: cestu k souboru
- `index`: výčet `FileStatus` pro změny od HEAD k indexu
- `worktree`: výčet `FileStatus` pro změny od indexu k pracovnímu stromu
- `origPath`, `renameScore`: nastaveno pro přejmenované položky, jinak `null`

Nesledované soubory mají v obou sloupcích `FileStatus::Untracked`. Ignorované soubory se neuvádějí.

```php
foreach ($repo->status() as $entry) {
    echo $entry->shortFormat() . "\n"; // "M  src/File.php", "?? notes.txt"
}
```

#### `statusPorcelainV2`

```php
public function statusPorcelainV2(): string
```

Strojově čitelný výstup stavu ve formátu git porcelain v2.

```php
echo $repo->statusPorcelainV2();
// 1 M. N... 000000 000000 000000 0000...0000 0000...0000 modified-file.txt
// ? untracked-file.txt
```

---

### Rozdíly

#### `diff`

```php
public function diff(?string $pathspec = null, string $algorithm = 'myers'): array
```

Porovná pracovní strom s indexem (nepřipravené změny). Vrátí pole objektů `DiffResult`. `$pathspec` filtruje podle jedné přesné cesty k souboru. `$algorithm` je `'myers'` (výchozí), `'patience'`, `'histogram'` nebo `'minimal'`; jakákoli jiná hodnota vyvolá `InvalidArgumentException`.

```php
$diffs = $repo->diff();

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

#### `diffStaged`

```php
public function diffStaged(?string $pathspec = null, string $algorithm = 'myers'): array
```

Porovná index s HEAD (připravené změny). Vrátí `DiffResult[]` a rozpozná přejmenování mezi smazanými a přidanými soubory.

Argument `$pathspec` se aktuálně ignoruje, takže se vrátí každý připravený soubor; před prvním commitem metoda vrátí prázdné pole ([#5](https://github.com/inline0/pitmaster/issues/5)).

```php
$staged = $repo->diffStaged();
```

#### `diffTree`

```php
public function diffTree(ObjectId $a, ObjectId $b, string $algorithm = 'myers'): array
```

Porovná dva stromy podle jejich `ObjectId`. Vrátí `DiffResult[]`. Zadejte ID stromů, ne ID commitů: ID commitu se nenačte jako strom a výsledkem bude prázdný výstup.

```php
$old = $repo->readObject($repo->resolve('HEAD~1')->hex);
$new = $repo->head();
$diffs = $repo->diffTree($old->tree, $new->tree);
```

---

### Historie

#### `log`

```php
public function log(int $limit = 50, ?ObjectId $from = null): array
```

Projde historii commitů od nejnovějšího podle času autora commitu. Vrátí `Commit[]`. Pokud je `$from` null, začne od HEAD. Pokud HEAD zatím nemá commit, vrátí prázdné pole.

```php
$commits = $repo->log(10);
```

#### `logAll`

```php
public function logAll(int $limit = 50): array
```

Projde commity dosažitelné ze všech referencí a HEAD, od nejnovějšího. Vrátí `Commit[]`.

#### `logOneline`

```php
public function logOneline(int $limit = 50, bool $all = false, ?string $path = null): array
```

Vrátí řádky protokolu ve formátu `git log --oneline` (`abc1234 Subject`), z HEAD, ze všech odkazů (`$all`) nebo filtrované podle cesty.

#### `logPath`

```php
public function logPath(string $path, int $limit = 50): array
```

Záznamy protokolu filtrované podle cesty k souboru. Vrátí pouze commity, jejichž rozdíl oproti prvnímu rodiči přidává, upravuje, maže nebo přejmenovává právě tento soubor. Cesty k adresářům neodpovídají.

Kontroluje se pouze nejnovějších `5 * $limit` commitů, takže ve výsledku mohou chybět starší commity, které se souboru týkají ([#7](https://github.com/inline0/pitmaster/issues/7)).

```php
$commits = $repo->logPath('src/Repository.php', 20);
```

---

### Sloučení

#### `merge`

```php
public function merge(string $branch, string $strategy = 'recursive'): MergeResult
public function mergeOctopus(array $branches): MergeResult
public function mergeContinue(): ObjectId
public function mergeAbort(): void
```

Sloučí větev (nebo libovolnou revizi) do HEAD. Automaticky rozpozná sloučení fast-forward. Při sloučení, které není fast-forward, zkontroluje konflikty na úrovni stromu a při čistém výsledku vytvoří merge commit. Při konfliktu zapíše stav sloučení ve formátu Git do indexu a pracovního stromu; vyřešte konflikty, připravte cesty a pak zavolejte `mergeContinue()` nebo `mergeAbort()`.

`$strategy` `'ours'` zaznamená merge commit, který zachová strom HEAD; jakákoli jiná hodnota použije výchozí rekurzivní sloučení. `mergeOctopus()` sloučí dvě nebo více větví do jednoho commitu. Pokud je některá větev v konfliktu, vrátí nečistý výsledek a nezapíše stav sloučení ani nevytvoří commit.

Sloučení větve, která je již obsažena v HEAD, vytvoří další merge commit místo zprávy „Již aktuální“ ([#6](https://github.com/inline0/pitmaster/issues/6)). Nepotvrzené změny ve sledovaných souborech se přepíší, jak je popsáno v části `checkout()`.

Vrátí `MergeResult` s těmito údaji:
- `clean`: zda sloučení proběhlo bez konfliktů
- `commitId`: ID merge commitu (při čistém výsledku)
- `conflictPaths`: pole cest ke konfliktním souborům (při nečistém výsledku)
- `mergedContents`: cesta ke konfliktnímu souboru a jeho obsahu se značkami konfliktu (při nečistém výsledku)

```php
$result = $repo->merge('feature/login');

if ($result->clean) {
    echo "Merged: {$result->commitId->hex}\n";
} else {
    echo "Conflicts in: " . implode(', ', $result->conflictPaths) . "\n";
    $repo->add('src/File.php');
    $repo->mergeContinue();
}
```

#### `mergeBase`

```php
public function mergeBase(ObjectId $a, ObjectId $b): ?ObjectId
```

Najde základ sloučení (nejnižšího společného předka) dvou commitů. Pokud neexistuje společný předek, vrátí null.

```php
$base = $repo->mergeBase(
    $repo->resolve('main'),
    $repo->resolve('feature/login'),
);
```

### Bisekce

```php
public function bisectStart(string $bad, string $good): ObjectId
public function bisectGood(?string $revision = null): ?ObjectId
public function bisectBad(?string $revision = null): ?ObjectId
public function bisectReset(): void
```

Binárním vyhledáváním najde commit, který zavedl změnu. `bisectStart()` zaznamená špatné a dobré revize, přepne na prvního kandidáta a vrátí jej. `bisectGood()` a `bisectBad()` označí aktuální HEAD (nebo `$revision`), přepnou na dalšího kandidáta a vrátí jej. Když zbývá jediný podezřelý commit, vrátí se a zůstane vybraný jako kandidát: jde o první chybný commit. `bisectReset()` ukončí relaci a vrátí se na větev nebo commit, kde začala.

```php
$candidate = $repo->bisectStart('HEAD', 'v1.0.0');
// test $candidate ...
$candidate = $repo->bisectBad();
$candidate = $repo->bisectGood();
$repo->bisectReset();
```

---

### Síť

#### `fetch`

```php
public function fetch(string $remote = 'origin', ?int $depth = null): void
```

Načte změny ze vzdáleného repozitáře. Stáhne nové objekty a aktualizuje vzdálené sledovací reference. Zadáním `$depth` prohloubíte nebo omezíte mělkou historii.

`fetch()` a metody `push*()` vyvolají `RuntimeException` u úchytu otevřeného pomocí `['processes' => false]`.

```php
$repo->fetch();
$repo->fetch('upstream');
```

#### `push`

```php
public function push(string $remote = 'origin', ?string $branch = null): void
public function pushForceWithLease(string $remote = 'origin', ?string $branch = null, ?ObjectId $expected = null): void
public function pushAtomic(string $remote = 'origin', array $branches = []): void
public function pushMirror(string $remote = 'origin'): void
```

Odešle aktuální větev (nebo zadanou větev) do vzdáleného repozitáře. K dispozici jsou varianty force-with-lease, atomic a mirror pro přísnější nebo širší aktualizace referencí.

```php
$repo->push();
$repo->push('origin', 'feature/login');
$repo->pushForceWithLease('origin', 'main', $repo->resolve('refs/remotes/origin/main'));
$repo->pushAtomic('origin', ['main', 'release']);
$repo->pushMirror();
```

---

### Pracovní stromy

#### `addWorktree`

```php
public function addWorktree(string $path, string $branch, ?ObjectId $from = null, ?string $name = null): Worktree
```

Přidá propojený pracovní strom. Pokud větev neexistuje, vytvoří ji, nastaví metadata pracovního stromu a vytvoří v něm soubory. Zadáním `$name` určíte předvídatelný identifikátor metadat, který se liší od názvu adresáře checkoutu.

```php
$wt = $repo->addWorktree('/tmp/review', 'feature/review');
$wt = $repo->addWorktree('/tmp/checkouts/review', 'feature/review', name: 'review-wt');
```

#### `removeWorktree`

```php
public function removeWorktree(string $pathOrName, bool $force = false): void
```

Odebere propojený pracovní strom. Zadáním `$force = true` jej odeberete i v případě, že je uzamčený.

#### `worktrees`

```php
public function worktrees(): array
```

Vypíše všechny pracovní stromy (hlavní i propojené). Vrátí `Worktree[]`.

```php
foreach ($repo->worktrees() as $wt) {
    echo "{$wt->path} [{$wt->branch}]\n";
}
```

---

### Konfigurace

#### `config`

```php
public function config(): GitConfig
```

Přístup ke konfiguraci git repozitáře. Čtení a zápis konfiguračních hodnot.

```php
$config = $repo->config();
$name = $config->get('user.name');
$config->set('user.email', 'new@example.com');
```

---

### Interní přístup

Tyto metody zpřístupňují interní komponenty pro pokročilé případy použití.

#### `objectDatabase`

```php
public function objectDatabase(): ObjectDatabase
```

Zpřístupní surovou databázi objektů (volné objekty a úložiště pack).

#### `refDatabase`

```php
public function refDatabase(): RefDatabase
```

Zpřístupní surovou databázi referencí (volné a zabalené reference).

---

## Třídy nižší úrovně

Tyto třídy nejsou obalené pomocí `Repository` a vytvářejí se z jeho interních komponent.

### `Pitmaster\Graph\Blame`

```php
public function blame(ObjectId $headId, string $path): array
```

Vrátí jednu položku na každý řádek `$path` v `$headId`: `['line' => int, 'hash' => string, 'author' => string, 'content' => string]`. `author` je úplný řetězec identity (`Name <email> timestamp timezone`).

```php
use Pitmaster\Graph\Blame;

$blame = new Blame($repo->objectDatabase());

foreach ($blame->blame($repo->resolve('HEAD'), 'src/File.php') as $line) {
    echo substr($line['hash'], 0, 8) . " {$line['content']}\n";
}
```

### `Pitmaster\Graph\Grep`

```php
public function grep(ObjectId $treeId, string $pattern, string $prefix = '', array $options = []): array
```

Prohledá bloby stromu. Pro každý odpovídající řádek vrátí `['path' => string, 'line' => int, 'content' => string]`. Možnosti: `regex` (interpretuje vzor jako vzor PCRE) a `ignore_case`. Neplatný regulární výraz vyvolá `InvalidArgumentException`.

```php
use Pitmaster\Graph\Grep;

$grep = new Grep($repo->objectDatabase());
$matches = $grep->grep($repo->head()->tree, 'TODO', '', ['ignore_case' => true]);
```

### `Pitmaster\Ref\Notes`

```php
public function get(ObjectId $commitId, string $notesRef = 'refs/notes/commits'): ?string
public function set(ObjectId $commitId, string $noteContent, string $notesRef = 'refs/notes/commits'): void
public function remove(ObjectId $commitId, string $notesRef = 'refs/notes/commits'): void
public function listAll(string $notesRef = 'refs/notes/commits'): array
public function merge(string $sourceRef, string $targetRef = 'refs/notes/commits'): void
```

Čte a zapisuje poznámky git uložené pod odkazem poznámek. `listAll()` vrací hash commitu odpovídající obsahu poznámky.

```php
use Pitmaster\Ref\Notes;

$notes = new Notes($repo->objectDatabase(), $repo->refDatabase());
$notes->set($repo->resolve('HEAD'), "Reviewed\n");
echo $notes->get($repo->resolve('HEAD'));
```
