
# Ühendamine

Pitmaster ühendab harusid kolmesuunalise ühendamise abil nagu `git merge`. See tuvastab kiiredasiedastuse võimalused, arvutab ühendamise baasid, ühendab puu- ja sisutasemel ning lisab failikonfliktide korral standardsed konfliktimarkerid.

## Ühendamise alused

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

Klass `MergeResult` on kirjutuskaitstud väärtusobjekt:

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

Kui ühendamine peatub konfliktide tõttu, kirjutatakse konfliktiolek indeksisse ja tööpuusse. Lahendage failid, lisage need `add()` abil ning kutsuge välja `$repo->mergeContinue()` või taastage ühendamiseelne olek käsuga `$repo->mergeAbort()`.

Enne ühendamist kinnitage või pange kohalikud muudatused kõrvale: ühendamine koostab tööpuu tulemusest uuesti ja kirjutab jälgitavates failides kinnitamata muudatused üle ([#2](https://github.com/inline0/pitmaster/issues/2)).

## Kiiredasiedastusega ühendamised

Kui praegune HEAD on sihtharu eelkäija, teeb Pitmaster kiiredasiedastusega ühendamise: see liigutab HEAD-i lihtsalt sihtsissekandele, ilma ühendamississekannet loomata.

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

Tagurpidi juhu tuvastamine pole veel teostatud: juba HEAD-is sisalduva haru ühendamisel luuakse muutumatu puuga uus ühendamississekanne, selle asemel et teatada "Already up to date" ([#6](https://github.com/inline0/pitmaster/issues/6)).

## Kolmeosaline ühendamine

Kui harud on lahknenud, teeb Pitmaster kolmesuunalise ühendamise:

1. Leia ühendamise baas (madalaim ühine eellane)
2. Võrdle puutasemel baasi meie ja baasi nende puuga
3. Tee mõlemas harus muudetud failide puhul sisutasemel ühendamine
4. Loo kahe vanemaga ühendamississekanne

```
Before:              After merge:

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

## Ühendamise baas

Ühendamise baas on kahe sissekande kõige hilisem ühine eellane. Pitmaster leiab selle sissekannete graafi läbides. Kui ühendamise baase on mitu (ristuv ajalugu), ühendab `merge()` need esmalt ja kasutab tulemust baasina.

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

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

Otse juurdepääsuks algoritmile `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);
```

## Haru ühendamise kontroll

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

## Konfliktimarkerid

Kui faili on muudetud mõlemas harus ja muudatused kattuvad, lisab Pitmaster standardsed konfliktimarkerid. `merge()` märgib pooled kui `HEAD` ja ühendatud haru nime:

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

Klass `ConflictMarker` ümbritseb kahte versiooni markeritega:

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

## Kolmesuunaline ühendamine sisutasemel

Klass `ThreeWayMerge` ühendab bloobide sisu (mitte faile):

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

See võtab kolm stringi (baasversiooni, meie versiooni ja nende versiooni), valikulised sildid ning konfliktistiili (vaikimisi `'merge'` või `'diff3'`, mis lisab ka baasiosa).

## Ühendamisstrateegiad

### Rekursiivne ühendamine

Vaikestrateegia (`$repo->merge($branch)`) käsitleb ristuvate ühendamiste ajalugu mitme ühendamisbaasiga. CLI aktsepteerib selle jaoks ka väärtusi `-s ort` ja `-s recursive`.

### Meie poole ühendamine

Salvestab ühendamississekande, jättes HEAD-i puu muutmata. Kasulik haruajaloo säilitamiseks ilma muudatusi kaasamata.

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

### Kaheksajalgühendamine

Ühendab kaks või enam haru üheks ühendamississekandeks. Kui mõnes harus tekib konflikt, tagastab see mittepuhas tulemuse, kirjutamata ühendamisolekut ega loomata sissekannet.

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

Klassid `RecursiveMerge`, `OursMerge` ja `OctopusMerge` moodulis `Pitmaster\Merge` on sisutaseme abivahendid; `Repository` rakendab ülaltoodud strateegiad ise.

## Rerere (salvestatud lahenduse taaskasutamine)

Pitmaster sisaldab iseseisvat klassi `Rerere`, mis salvestab lahendused git-i kataloogistruktuuri `rr-cache` järgi:

```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()` ei kutsu seda välja: lahendused salvestatakse ja taasesitatakse ainult siis, kui teie kood seda teeb. `isEnabled()` otsib stringi `rerere.enabled = true` failist `.git/config` ega tunne ära sektsiooni `[rerere]`, mille kirjutab `git config rerere.enabled true` ([#20](https://github.com/inline0/pitmaster/issues/20)).

## Puutasemel ühendamise voog

Ühendamise täielik protsess:

1. `MergeBase::findAll()` leiab ühised eellased
2. Võrdleb baasi, meie ja nende puid tee kaupa
3. Kui faili muudeti ainult ühes harus, võtab selle muudatuse üle
4. Kui faili muudeti mõlemas harus:
   - Kui mõlemad muudeti ühtemoodi, võtab ükskõik kumma muudatuse (need kattuvad)
   - Kui muudatused erinevad, käivitab sisul `ThreeWayMerge::merge()`
5. Kui kõik ühendamised õnnestuvad, koostab ühendatud puu ja loob ühendamississekande
6. Kui tekib konflikt, tagastab `MergeResult` koos väärtusega `clean = false` ja konfliktsete radadega

## CLI kasutamine

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

Eduka toimingu väljund:
```
Merge successful.
```

Väljund konflikti korral:
```
CONFLICT in: src/File.php, src/Other.php
```
