
# Zlúčenie

Pitmaster vykonáva zlúčenie vetiev trojcestným zlúčením, podobne ako `git merge`. Rozpoznáva možnosti rýchleho posunu, vypočítava základne zlúčenia, vykonáva zlúčenia na úrovni stromov aj obsahu a pri konfliktoch v súboroch vytvára štandardné značky konfliktov.

## Základné zlúčenie

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

Trieda `MergeResult` je objekt hodnoty iba na čítanie:

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

Keď sa zlúčenie zastaví pre konflikty, stav konfliktov sa zapíše do indexu a pracovného stromu. Vyriešte konflikty v súboroch, pridajte `add()` do indexu a zavolajte `$repo->mergeContinue()` alebo zavolajte `$repo->mergeAbort()`, aby ste obnovili stav pred zlúčením.

Pred zlúčením potvrďte alebo odložte miestne zmeny: zlúčenie znovu zostaví pracovný strom z výsledku a prepíše nepotvrdené zmeny v sledovaných súboroch ([#2](https://github.com/inline0/pitmaster/issues/2)).

## Zlúčenia rýchlym posunom

Keď je aktuálny HEAD predkom cieľovej vetvy, Pitmaster vykoná zlúčenie rýchlym posunom: jednoducho presunie HEAD na cieľový commit bez vytvorenia commitu zlúčenia.

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

Opačný prípad sa zatiaľ nerozpoznáva: zlúčením vetvy, ktorú HEAD už obsahuje, sa vytvorí nový commit zlúčenia s nezmeneným stromom namiesto oznámenia „Už aktuálne“ ([#6](https://github.com/inline0/pitmaster/issues/6)).

## Trojstranné zlúčenie

Keď sa vetvy rozídu, Pitmaster vykoná trojcestné zlúčenie:

1. Nájdite základňu zlúčenia (najnižšieho spoločného predka)
2. Vypočítajte rozdiely medzi základňou a našou vetvou a medzi základňou a ich vetvou na úrovni stromov
3. Pri každom súbore zmenenom v oboch vetvách vykonajte zlúčenie na úrovni obsahu
4. Vytvorte commit zlúčenia s dvoma rodičmi

```
Before:              After merge:

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

## Základňa zlúčenia

Základňa zlúčenia je najnovší spoločný predok dvoch commitov. Pitmaster ju nájde prechádzaním grafu commitov. Ak existuje viacero základní zlúčenia (história s kríženiami), `merge()` ich najprv zlúči a výsledok použije ako základňu.

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

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

Priamy prístup k algoritmu `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);
```

## Kontrola zlúčenia vetvy

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

## Značky konfliktov

Keď je súbor upravený v oboch vetvách a zmeny sa prekrývajú, Pitmaster vytvorí štandardné značky konfliktov. `merge()` označí strany ako `HEAD` a názvom zlúčenej vetvy:

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

Trieda `ConflictMarker` oba varianty uzavrie do značiek:

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

## Trojcestné zlúčenie na úrovni obsahu

Trieda `ThreeWayMerge` zlúči obsah objektov blob (nie súbory):

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

Prijíma tri reťazce (základnú verziu, našu verziu a ich verziu) spolu s voliteľnými označeniami a štýlom konfliktov (predvolene `'merge'`, prípadne `'diff3'`, ktorý zahŕňa aj časť so základnou verziou).

## Stratégie zlúčenia

### Rekurzívne zlúčenie

Predvolená stratégia (`$repo->merge($branch)`) spracúva histórie zlúčení s kríženiami a viacerými základňami. Trieda CLI pre ňu prijíma aj `-s ort` a `-s recursive`.

### Zlúčenie našej vetvy

Vytvorí commit zlúčenia, ktorý ponechá strom HEAD nezmenený. Je užitočný na udržiavanie histórie vetvy bez zahrnutia zmien.

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

### Zlúčenie Octopus

Zlúči dve alebo viac vetiev do jedného commitu zlúčenia. Ak v niektorej vetve dôjde ku konfliktu, vráti nečistý výsledok bez zápisu stavu zlúčenia alebo vytvorenia commitu.

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

Triedy `RecursiveMerge`, `OursMerge` a `OctopusMerge` v `Pitmaster\Merge` sú pomocné nástroje na zlúčenie obsahu; `Repository` implementuje uvedené stratégie samostatne.

## Rerere (opätovné použitie zaznamenaného riešenia)

Pitmaster obsahuje samostatnú triedu `Rerere`, ktorá ukladá riešenia v rozložení `rr-cache` v 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()` ju nevolá: riešenia sa zaznamenávajú a opakovane používajú iba vtedy, keď to urobí váš kód. `isEnabled()` hľadá doslovný text `rerere.enabled = true` v `.git/config` a nerozpoznáva sekciu `[rerere]`, ktorú zapisuje `git config rerere.enabled true` ([#20](https://github.com/inline0/pitmaster/issues/20)).

## Priebeh zlúčenia na úrovni stromov

Celý proces zlúčenia:

1. `MergeBase::findAll()` nájde spoločných predkov
2. Základný strom, náš strom a ich strom sa porovnávajú cesta po ceste
3. Pri súboroch zmenených iba v jednej vetve: použije sa táto zmena
4. Pri súboroch zmenených v oboch vetvách:
   - Ak sa zmenili rovnako: použije sa ktorákoľvek verzia (sú zhodné)
   - Ak sa zmeny líšia: spustí sa `ThreeWayMerge::merge()` nad obsahom
5. Ak sú všetky zlúčenia čisté: zostaví sa zlúčený strom a vytvorí sa commit zlúčenia
6. Ak sa vyskytnú konflikty: vráti sa `MergeResult` s `clean = false` a cestami ku konfliktom

## Používanie CLI

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

Výstup pri úspechu:
```
Merge successful.
```

Výstup pri konflikte:
```
CONFLICT in: src/File.php, src/Other.php
```
