
# Îmbinare

Pitmaster îmbină ramuri printr-o îmbinare în trei direcții, la fel ca `git merge`. Detectează posibilitățile de fast-forward, calculează bazele de îmbinare, îmbină arbori și conținut și generează marcaje de conflict standard când fișierele intră în conflict.

## Îmbinare de bază

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

if ($result->clean) {
    echo "Merged successfully: {$result->commitId->hex}\n";
} else {
    echo "Conflicts:\n";
    foreach ($result->conflictPaths as $path) {
        echo "  {$path}\n";
    }
}
```

## MergeResult

Clasa `MergeResult` este un obiect valoare doar pentru citire:

```php
use Pitmaster\Merge\MergeResult;

$result->clean;           // bool: true if merge completed without conflicts
$result->commitId;        // ?ObjectId: the merge commit (null if conflicts)
$result->conflictPaths;   // array: list of file paths with conflicts
$result->mergedContents;  // array: path => content with conflict markers (if conflicts)
```

Când îmbinarea se oprește din cauza conflictelor, starea conflictului este scrisă în index și în arborele de lucru. Rezolvați conflictele din fișiere, adăugați-le la staging cu `add()` și apelați `$repo->mergeContinue()` sau apelați `$repo->mergeAbort()` pentru a restaura starea dinaintea îmbinării.

Înainte de îmbinare, faceți commit sau stash pentru modificările locale: îmbinarea reconstruiește arborele de lucru pornind de la rezultat și suprascrie modificările necomise din fișierele urmărite ([#2](https://github.com/inline0/pitmaster/issues/2)).

## Îmbinări fast-forward

Când HEAD-ul actual este un strămoș al ramurii țintă, Pitmaster efectuează o îmbinare fast-forward: mută pur și simplu HEAD la commitul țintă, fără să creeze un commit de îmbinare.

```
Before:         After fast-forward:

A---B (main)    A---B---C---D (main)
     \
      C---D (feature)
```

```php
$result = $repo->merge('feature');
// $result->clean === true
// $result->commitId points to D
// No merge commit created
```

Cazul invers nu este detectat încă: îmbinarea unei ramuri pe care HEAD o conține deja creează un commit de îmbinare cu un arbore neschimbat, în loc să raporteze „Already up to date” ([#6](https://github.com/inline0/pitmaster/issues/6)).

## Îmbinare în trei direcții

Când ramurile au diverjat, Pitmaster efectuează o îmbinare în trei direcții:

1. Găsește baza de îmbinare (cel mai apropiat strămoș comun)
2. Compară baza cu versiunea noastră și cu a lor, la nivel de arbore
3. Pentru fiecare fișier modificat în ambele ramuri, efectuează o îmbinare la nivel de conținut
4. Creează un commit de îmbinare cu doi părinți

```
Before:              After merge:

      C---D (feature)         C---D
     /                       /     \
A---B---E---F (main)   A---B---E---F---G (main)
```

## Baza de îmbinare

Baza de îmbinare este cel mai recent strămoș comun al două commituri. Pitmaster o găsește parcurgând graful commiturilor. Când există mai multe baze de îmbinare (istoric încrucișat), `merge()` le îmbină mai întâi și folosește rezultatul ca bază.

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

if ($base !== null) {
    echo "Common ancestor: {$base->hex}\n";
}
```

Acces direct la algoritmul `MergeBase`:

```php
use Pitmaster\Merge\MergeBase;

$finder = new MergeBase($repo->objectDatabase());
$base = $finder->find($commitA, $commitB);

// All merge bases (criss-cross histories can have more than one)
$bases = $finder->findAll($commitA, $commitB);

// Check ancestry
$isAncestor = $finder->isAncestor($oldCommit, $newCommit);
```

## Verificarea îmbinării ramurilor

```php
if ($repo->isBranchMerged('feature/done')) {
    // All commits in feature/done are reachable from default branch
    $repo->deleteBranch('feature/done');
}

// Check against a specific target
if ($repo->isBranchMerged('feature/done', 'develop')) {
    // Merged into develop
}
```

## Marcaje de conflict

Când un fișier este modificat în ambele ramuri și modificările se suprapun, Pitmaster generează marcaje de conflict standard. `merge()` etichetează versiunile ca `HEAD` și cu numele ramurii îmbinate:

```
<<<<<<< HEAD
    return $this->value + 1;
=======
    return $this->value * 2;
>>>>>>> feature
```

Clasa `ConflictMarker` încadrează două versiuni în marcaje:

```php
use Pitmaster\Merge\ConflictMarker;

$marked = ConflictMarker::mark($oursContent, $theirsContent, 'HEAD', 'feature');

// diff3 style, with the base section
$marked = ConflictMarker::mark($oursContent, $theirsContent, 'HEAD', 'feature', $baseContent, 'base');
```

## Îmbinare în trei direcții la nivel de conținut

Clasa `ThreeWayMerge` îmbină conținutul bloburilor (nu fișierele):

```php
use Pitmaster\Merge\ThreeWayMerge;

$result = ThreeWayMerge::merge($baseContent, $oursContent, $theirsContent, 'HEAD', 'feature');

$result['content'];   // merged text, with conflict markers if needed
$result['clean'];     // true when nothing conflicted
$result['conflicts']; // number of conflict regions
```

Primește trei șiruri (versiunea de bază, versiunea noastră și versiunea lor), etichete opționale și un stil de conflict (`'merge'` în mod implicit sau `'diff3'` pentru a include secțiunea de bază).

## Strategii de îmbinare

### Îmbinare recursivă

Strategia implicită (`$repo->merge($branch)`) gestionează istoricul încrucișat cu mai multe baze de îmbinare. CLI acceptă și `-s ort` și `-s recursive` pentru aceasta.

### Îmbinare Ours

Înregistrează un commit de îmbinare care păstrează arborele HEAD neschimbat. Utilă pentru menținerea istoricului ramurilor fără a integra modificări.

```php
$result = $repo->merge('feature/old', 'ours');
```

### Îmbinare Octopus

Îmbină două sau mai multe ramuri într-un singur commit de îmbinare. Dacă vreo ramură intră în conflict, returnează un rezultat necurat fără să scrie starea îmbinării sau să creeze un commit.

```php
$result = $repo->mergeOctopus(['feature/a', 'feature/b', 'feature/c']);
```

Clasele `RecursiveMerge`, `OursMerge` și `OctopusMerge` din `Pitmaster\Merge` sunt ajutoare pentru îmbinarea la nivel de conținut; `Repository` implementează singură strategiile de mai sus.

## Rerere (reutilizarea rezolvării înregistrate)

Pitmaster include o clasă `Rerere` autonomă, care stochează rezolvările în structura `rr-cache` a lui git:

```php
use Pitmaster\Merge\Rerere;

$rerere = new Rerere($repo->gitDir());

if ($rerere->isEnabled()) {                     // rerere.enabled = true in .git/config
    $rerere->record($conflicted, $resolved);    // remember a resolution
    $resolved = $rerere->resolve($conflicted);  // replay it, or null
}
```

`merge()` nu o apelează: rezolvările sunt înregistrate și reluate numai când codul dumneavoastră face acest lucru. `isEnabled()` caută textul literal `rerere.enabled = true` în `.git/config` și nu recunoaște secțiunea `[rerere]` scrisă de `git config rerere.enabled true` ([#20](https://github.com/inline0/pitmaster/issues/20)).

## Fluxul îmbinării la nivel de arbore

Procesul complet de îmbinare:

1. `MergeBase::findAll()` găsește strămoșii comuni
2. Arborii de bază, al nostru și al lor sunt comparați cale cu cale
3. Pentru fișierele modificate doar într-o ramură: se preia acea modificare
4. Pentru fișierele modificate în ambele ramuri:
   - Dacă au fost modificate la fel: se preia oricare (sunt identice)
   - Dacă modificările diferă: se execută `ThreeWayMerge::merge()` asupra conținutului
5. Dacă toate îmbinările sunt curate: se construiește arborele îmbinat și se creează un commit de îmbinare
6. Dacă există conflicte: se returnează `MergeResult` cu `clean = false` și căile care intră în conflict

## Utilizarea CLI

```bash
./vendor/bin/pitmaster merge feature/login
```

Rezultat în caz de reușită:
```
Merge successful.
```

Rezultatul în caz de conflict:
```
CONFLICT in: src/File.php, src/Other.php
```
