
# PHP API

## `Pitmaster\Pitmaster`

Clasa `Pitmaster\Pitmaster` este punctul de intrare static. Oferă metode factory pentru deschiderea, crearea și clonarea depozitelor, precum și funcții ajutătoare pentru detectare.

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

### `open`

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

Deschide un depozit existent în `$path`. Calea trebuie să fie rădăcina arborelui de lucru (care conține `.git/`). Sunt acceptate și worktree-urile asociate (unde `.git` este un fișier care conține `gitdir: <path>`) și depozitele bare (unde `$path` este chiar directorul `.git`).

`$options` acceptă două valori booleene, ambele `true` în mod implicit:

- `hooks`: rulează scripturile `.git/hooks`. Transmiteți `false` pentru a le omite pentru acest handle.
- `processes`: permite orice pornește un proces sau deschide un transport de rețea. Transmiteți `false` pentru a dezactiva hook-urile, hook-ul fsmonitor, clonarea, fetch, push și transportul de procese SSH. Citirea și scrierea locală continuă să funcționeze.

Aruncă `InvalidArgumentException` dacă calea nu este un depozit git.

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

Inițializează un depozit nou în `$path`. Creează structura de directoare `.git` cu `objects/`, `refs/heads/`, `refs/tags/`, `hooks/`, `info/`, `HEAD` (care indică spre `refs/heads/main`) și un `config` implicit.

`$objectFormat` este `'sha1'` sau `'sha256'`. Un depozit SHA-256 primește `repositoryformatversion = 1` și `extensions.objectformat = sha256` în configurația sa. Orice altă valoare aruncă `InvalidArgumentException`. `$options` acceptă aceleași chei ca `open()`.

Aruncă `RuntimeException` dacă există deja un depozit în această cale.

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

Clonează un depozit la distanță. Inițializează un depozit nou, descoperă referințele la distanță, preia fișierul pack, configurează ramurile de urmărire la distanță și materializează arborele de lucru. URL-urile SSH (`ssh://...` sau `user@host:path`) folosesc transportul SSH; celelalte URL-uri folosesc HTTP inteligent și revin la HTTP simplu dacă schimbul inteligent eșuează. Transmiteți `$depth` pentru o clonare superficială.

Aruncă `RuntimeException` când `$options['processes']` este `false`. Dacă clonarea eșuează și `$path` nu exista anterior, directorul creat parțial este eliminat.

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

Returnează `['processes' => false, 'hooks' => false]`, pentru medii de execuție care nu trebuie să pornească procese pe gazdă. Transmiteți-l către `open()` sau `init()`.

### `isRepository`

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

Verifică dacă o cale este un depozit git. Returnează `true` pentru depozitele obișnuite (directorul `.git/`), worktree-urile asociate (fișierul `.git`) și depozitele bare (fișierul `HEAD` prezent).

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

### `isWorktree`

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

Verifică dacă o cale este un worktree asociat (nu depozitul principal). Returnează `true` numai dacă `.git` este un fișier care conține o referință `gitdir:`.

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

### `commonGitDir`

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

Rezolvă directorul comun git pornind de la orice cale de checkout. Pentru depozitele obișnuite, acesta este directorul `.git`. Pentru worktree-urile asociate, este directorul git partajat, care conține obiectele, configurația și packed-refs. Returnează `null` dacă această cale nu este un depozit.

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

---

## `Pitmaster\Repository`

Clasa `Pitmaster\Repository` este handle-ul principal pentru toate operațiile git. Obțineți unul prin `Pitmaster::open()`, `Pitmaster::init()` sau `Pitmaster::clone()`.

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

### Accesori pentru căi

#### `gitDir`

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

Returnează directorul git specific worktree-ului. Pentru depozitele obișnuite, acesta este `.git/`. Pentru worktree-urile asociate, este `.git/worktrees/<name>/`.

#### `commonGitDir`

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

Returnează directorul git partajat. Pentru depozitele obișnuite, este același cu `gitDir()`. Pentru worktree-urile asociate, este directorul `.git/` al depozitului principal (în care se află obiectele, configurația și packed-refs).

#### `workDir`

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

Returnează calea rădăcinii arborelui de lucru.

#### `isLinkedWorktree`

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

Returnează `true` dacă acest handle de depozit este un worktree asociat.

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

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

Indică dacă depozitul nu are arbore de lucru și care dintre opțiunile `hooks` / `processes` sunt active pentru acest handle. `hooksEnabled()` este `false` ori de câte ori procesele sunt dezactivate.

---

### Obiecte

#### `readObject`

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

Citește orice obiect folosind hash-ul hexazecimal complet (40 de caractere sau 64 într-un depozit SHA-256). Hash-urile abreviate nu sunt acceptate. Returnează o instanță `Blob`, `Tree`, `Commit` sau `Tag`. Caută mai întâi în obiectele loose, apoi în fișierele pack.

Aruncă `ObjectNotFoundException` dacă hash-ul nu este găsit.

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

#### `writeObject`

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

Scrie un obiect în stocarea obiectelor loose. Returnează `ObjectId` calculat.

```php
use Pitmaster\Object\Blob;

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

#### `catFile`

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

Returnează conținutul brut al unui obiect, echivalent cu `git cat-file -p`.

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

#### `objectExists`

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

Verifică dacă un obiect există în depozit (loose sau împachetat).

#### `listObjects`

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

Listează toate hash-urile obiectelor din depozit. Returnează un tablou de șiruri hexazecimale.

---

### Referințe

#### `head`

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

Returnează commitul HEAD curent. Urmărește referințele simbolice (HEAD -> refs/heads/main -> hash-ul commitului).

Aruncă `RuntimeException` dacă HEAD nu indică spre un commit valid (e.g., depozit gol).

#### `branch`

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

Fără argumente, returnează numele ramurii curente (e.g., `'main'`) sau `null` dacă HEAD este detașat.

Dacă se transmite numele unei ramuri, îl rezolvă la hash-ul commitului (șir hexazecimal) sau returnează `null` dacă ramura nu există.

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

#### `branches`

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

Returnează un tablou sortat cu toate numele ramurilor (fără prefixul `refs/heads/`).

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

#### `tags`

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

Returnează un tablou sortat cu toate numele etichetelor (fără prefixul `refs/tags/`).

#### `resolve`

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

Rezolvă o expresie de revizie la un `ObjectId`. Sunt acceptate:
- Hash-uri hexazecimale complete (40 de caractere sau 64 pentru SHA-256). Hash-urile abreviate, precum `abc1234`, nu sunt rezolvate.
- `HEAD`
- Nume de ramuri (`main`, `feature/login`)
- Nume de etichete (`v1.0.0`)
- Căi complete de referință (`refs/heads/main`)
- Expresii de revizie (`HEAD~3`, `main^2`)

Aruncă `RuntimeException` dacă revizia nu poate fi rezolvată.

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

#### `allRefs`

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

Returnează toate referințele ca tablou asociativ cu numele referinței asociat hash-ului hexazecimal.

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

#### `updateRef`

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

Actualizează o referință pentru a indica spre o nouă țintă.

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

#### `createBranch`

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

Creează o ramură nouă. Dacă `$from` este null, creează ramura pornind de la HEAD-ul curent.

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

#### `deleteBranch`

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

Șterge o ramură după nume. Aruncă `RuntimeException` dacă ramura are checkout sau nu există. Spre deosebire de `git branch -d`, nu verifică dacă ramura a fost integrată.

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

#### `createLightweightTag`

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

Creează o etichetă lightweight. Dacă `$target` este null, aplică eticheta direct HEAD-ului curent.

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

Creează o etichetă cu adnotări. Dacă `$target` este null, aplică eticheta HEAD-ului curent. Returnează `ObjectId` obiectului etichetă.

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

#### `deleteTag`

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

Șterge o etichetă după nume.

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

#### `packRefs`

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

Rescrie fișierul `packed-refs` partajat folosind setul curent de referințe loose și elimină referințele loose partajate corespunzătoare. Pentru worktree-urile asociate, scrie în directorul comun git.

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

#### `defaultBranch`

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

Rezolvă ramura implicită a depozitului. Verifică mai întâi referința simbolică HEAD la distanță, apoi HEAD-ul local și, în final, revine la `main` sau `master`.

#### `isBranchMerged`

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

Verifică dacă o ramură este integrată complet într-o altă ramură (implicit, în ramura implicită).

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

#### `checkout`

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

Comută ramurile sau detașează HEAD. Actualizează HEAD-ul, indexul și arborele de lucru. `$target` poate fi un nume de ramură, o etichetă, un hash complet sau o expresie de revizie; orice nu este o ramură detașează HEAD.

Aruncă `RuntimeException` dacă o modificare locală (în staging sau nu) ori un fișier neurmărit se află într-o cale care diferă între arborele curent și cel țintă.

Modificările necomise din alte fișiere urmărite nu sunt păstrate: indexul și arborele de lucru sunt reconstruite din arborele țintă, astfel că editările fișierelor identice în ambele versiuni se pierd, în timp ce git le-ar păstra ([#2](https://github.com/inline0/pitmaster/issues/2)). Faceți commit sau stash înainte. `merge()`, `cherryPick()`, `revert()`, `rebase()` și metodele bisect reconstruiesc arborele de lucru în același mod.

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

---

### Index

#### `index`

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

Citește și returnează indexul curent (zona de staging) din `.git/index`.

#### `add`

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

Adaugă fișiere în staging. Citește fiecare fișier din arborele de lucru, creează un obiect blob și actualizează indexul. Fiecare argument trebuie să fie o cale de fișier (sau legătură simbolică) relativă la rădăcina arborelui de lucru; directoarele și globurile nu sunt extinse, iar dacă lipsește un fișier se aruncă `RuntimeException`.

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

#### `remove`

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

Elimină căile urmărite atât din index, cât și din arborele de lucru. Acceptă `--cached` și `-r` / `--recursive` în lista de argumente pentru un comportament de tip 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
```

Mută/redenumște un fișier atât în arborele de lucru, cât și în index.

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

---

### Commituri

#### `commit`

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

Creează un commit din indexul curent. Construiește o ierarhie de arbori din intrările indexului, creează obiectul commit cu HEAD drept părinte (dacă există) și actualizează HEAD. Returnează `ObjectId` noului commit.

`$message` poate fi `null` numai dacă o operație de merge, cherry-pick, revert sau rebase s-a oprit din cauza unui conflict; atunci se folosește mesajul pregătit. În caz contrar, un mesaj `null` aruncă `RuntimeException('Commit message required')`. Operația de commit aruncă o eroare și dacă indexul conține căi neîmbinate, dacă indexul este gol într-un depozit fără commituri sau dacă arborele este identic cu cel din HEAD.

Parametrul `$author` este un șir complet de autor git (`Name <email> timestamp timezone`). Dacă este null, se determină din variabilele de mediu, constante și `.git/config`, în ordinea descrisă în [Noțiuni de bază](https://pitmaster.inline0.dev/ro/docs/getting-started).

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

#### `show`

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

Afișează un commit sau un obiect similar și diferențele față de primul părinte. Când revizia se rezolvă la o etichetă cu adnotări, valoarea returnată include și `['tag' => Tag]`, iar `commit` este commitul țintă dereferențiat.

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

Resetează HEAD la un commit. Moduri:
- `'soft'`: mută doar HEAD
- `'mixed'`: mută HEAD + resetează indexul (implicit)
- `'hard'`: mută HEAD + resetează indexul + resetează arborele de lucru

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

Restaurează o cale din index sau dintr-o revizie sursă specifică. Dacă nu este setat niciun indicator, Pitmaster restaurează worktree-ul din index (sau din `$source`, dacă este specificat). `staged: true` restaurează indexul din HEAD (sau din `$source`) și lasă worktree-ul neschimbat; transmiteți `staged: true, worktree: true` pentru a le restaura pe amândouă.

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

Aplică un commit ca un commit nou pe ramura curentă, păstrând autorul original. Dacă operația se oprește din cauza conflictelor, rezolvați-le, adăugați căile în staging, apoi apelați `cherryPickContinue()` sau `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
```

Creează un commit care anulează un alt commit. Dacă revert-ul se oprește din cauza conflictelor, rezolvați-le, adăugați căile în staging, apoi apelați `revertContinue()` sau `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
```

Rebazează ramura curentă peste o altă revizie. În prezent, Pitmaster acoperă rebase-uri liniare cu o stare de oprire de tip Git pentru conflicte, plus continuarea, anularea și omiterea operației. HEAD trebuie să indice spre o ramură.

`rebase()`, `rebaseContinue()` și `rebaseSkip()` returnează `['success' => bool, 'commits' => int, 'conflicts' => list<string>]`: dacă rebase-ul s-a încheiat, câte commituri au fost aplicate și căile cu conflicte atunci când operația s-a oprit.

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

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

---

### Stare

#### `status`

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

Calculează starea arborelui de lucru. Returnează un tablou de obiecte `StatusEntry`, fiecare conținând:
- `path`: calea fișierului
- `index`: enumerarea `FileStatus` pentru modificările dintre HEAD și index
- `worktree`: enumerarea `FileStatus` pentru modificările dintre index și worktree
- `origPath`, `renameScore`: setate pentru intrările redenumite, altfel `null`

Fișierele neurmărite au `FileStatus::Untracked` în ambele coloane. Fișierele ignorate nu sunt raportate.

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

#### `statusPorcelainV2`

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

Rezultatul stării, care poate fi citit automat, în formatul porcelain git pentru v2.

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

---

### Diferențe

#### `diff`

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

Compară arborele de lucru cu indexul (modificări nestagiate). Returnează un tablou de obiecte `DiffResult`. `$pathspec` filtrează după o singură cale exactă de fișier. `$algorithm` este `'myers'` (implicit), `'patience'`, `'histogram'` sau `'minimal'`; orice altă valoare aruncă `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
```

Compară indexul cu HEAD (modificări în staging). Returnează `DiffResult[]`, cu detectarea redenumirilor între fișierele șterse și cele adăugate.

Argumentul `$pathspec` este momentan ignorat, așadar sunt returnate toate fișierele din staging, iar metoda returnează un tablou gol înainte de primul commit ([#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
```

Compară doi arbori folosind `ObjectId`. Returnează `DiffResult[]`. Transmiteți ID-urile arborilor, nu ID-urile commiturilor: un ID de commit nu este citit ca arbore și produce un rezultat gol.

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

---

### Jurnal

#### `log`

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

Parcurge istoricul commiturilor, începând cu cel mai recent după marcajul temporal al autorului commitului. Returnează `Commit[]`. Dacă `$from` este null, începe de la HEAD. Returnează un tablou gol dacă HEAD nu are încă un commit.

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

#### `logAll`

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

Parcurge commiturile accesibile din fiecare referință și din HEAD, începând cu cel mai recent. Returnează `Commit[]`.

#### `logOneline`

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

Returnează liniile jurnalului în formatul `git log --oneline` (`abc1234 Subject`), din HEAD, din toate referințele (`$all`) sau filtrate după cale.

#### `logPath`

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

Jurnal filtrat după o cale de fișier. Returnează numai commiturile ale căror diferențe față de primul părinte adaugă, modifică, șterg sau redenumesc acel fișier exact. Căile directoarelor nu corespund.

Sunt examinate doar cele mai recente `5 * $limit` commituri, așadar commiturile mai vechi care modifică fișierul pot lipsi din rezultat ([#7](https://github.com/inline0/pitmaster/issues/7)).

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

---

### Îmbinare

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

Îmbină o ramură (sau orice revizie) în HEAD. Detectează automat îmbinările fast-forward. Pentru îmbinările care nu sunt fast-forward, detectează conflictele la nivelul arborelui și creează un commit de îmbinare dacă nu există conflicte. La oprirea din cauza conflictelor, scrie starea de îmbinare de tip Git în index și în worktree; rezolvați conflictele, adăugați căile în staging, apoi apelați `mergeContinue()` sau `mergeAbort()`.

`$strategy` `'ours'` înregistrează un commit de îmbinare care păstrează arborele din HEAD; orice altă valoare folosește îmbinarea recursivă implicită. `mergeOctopus()` îmbină două sau mai multe ramuri într-un singur commit. Dacă o ramură are conflicte, returnează un rezultat cu conflicte fără a scrie starea de îmbinare sau a crea un commit.

Îmbinarea unei ramuri deja incluse în HEAD creează un alt commit de îmbinare în loc să raporteze „Already up to date” ([#6](https://github.com/inline0/pitmaster/issues/6)). Modificările necomise din fișierele urmărite sunt suprascrise conform descrierii de la `checkout()`.

Returnează un `MergeResult` cu:
- `clean`: dacă îmbinarea a reușit fără conflicte
- `commitId`: ID-ul commitului de îmbinare (dacă este curat)
- `conflictPaths`: matricea căilor fișierelor cu conflicte (dacă nu este curat)
- `mergedContents`: calea conflictuală către conținutul fișierului cu marcaje de conflict (dacă nu este curat)

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

Găsește baza de îmbinare (cel mai jos strămoș comun) a două commituri. Returnează null dacă nu există niciun strămoș comun.

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

### Bisecție

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

Caută binar commitul care a introdus o modificare. `bisectStart()` înregistrează reviziile cu probleme și bune, face checkout la primul candidat și îl returnează. `bisectGood()` și `bisectBad()` marchează HEAD-ul curent (sau `$revision`), apoi fac checkout la următorul candidat și îl returnează. Când rămâne un singur suspect, se returnează acel commit, care rămâne candidatul: este primul commit cu probleme. `bisectReset()` încheie sesiunea și revine la ramura sau commitul de la care a început.

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

---

### Rețea

#### `fetch`

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

Preia date de la o sursă la distanță. Descarcă obiecte noi și actualizează referințele de urmărire la distanță. Transmiteți `$depth` pentru a extinde sau limita un istoric superficial.

`fetch()` și metodele `push*()` aruncă `RuntimeException` pentru un handle deschis cu `['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
```

Împinge ramura curentă (sau una specificată) către o sursă la distanță. Sunt disponibile variantele force-with-lease, atomice și mirror pentru actualizări de referințe mai stricte sau mai ample.

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

---

### Worktree-uri

#### `addWorktree`

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

Adaugă un worktree conectat. Creează ramura dacă aceasta nu există, configurează metadatele worktree-ului și materializează fișierele arborelui de lucru. Transmiteți `$name` când aveți nevoie de un slug determinist pentru metadate, diferit de numele de bază al directorului checkout-ului.

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

Elimină un worktree conectat. Folosiți `$force = true` pentru a-l elimina chiar dacă este blocat.

#### `worktrees`

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

Listează toate worktree-urile (principal + conectate). Returnează `Worktree[]`.

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

---

### Configurare

#### `config`

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

Accesează configurația git a depozitului. Citește și scrie valorile de configurare.

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

---

### Acces intern

Aceste metode expun componente interne pentru cazuri de utilizare avansate.

#### `objectDatabase`

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

Accesează baza brută de obiecte (depozite loose și pack).

#### `refDatabase`

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

Accesează baza brută de referințe (referințe loose și packed).

---

## Clase de nivel inferior

Aceste clase nu sunt încapsulate de `Repository` și sunt construite din componentele sale interne.

### `Pitmaster\Graph\Blame`

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

Returnează câte o intrare pentru fiecare linie din `$path` la `$headId`: `['line' => int, 'hash' => string, 'author' => string, 'content' => string]`. `author` este șirul complet de identitate (`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
```

Caută în bloburile unui arbore. Returnează `['path' => string, 'line' => int, 'content' => string]` pentru fiecare linie care corespunde. Opțiuni: `regex` (tratează modelul ca expresie PCRE) și `ignore_case`. O expresie regulată nevalidă aruncă `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
```

Citește și scrie notele git stocate sub o referință de note. `listAll()` returnează hashul commitului către conținutul notei.

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