
# Sammanfogning

Pitmaster sammanfogar grenar med en tredelad sammanfogning, liksom `git merge`. Den identifierar möjligheter till snabbspolning, beräknar sammanfogningsbaser, sammanfogar på träd- och innehållsnivå och skapar standardmässiga konfliktmarkörer när filer hamnar i konflikt.

## Grundläggande sammanfogning

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

Klassen `MergeResult` är ett skrivskyddat värdeobjekt:

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

När sammanfogningen avbryts på grund av konflikter skrivs konfliktstatusen till indexet och arbetsträdet. Lös filerna, `add()` dem och anropa `$repo->mergeContinue()`, eller anropa `$repo->mergeAbort()` för att återställa tillståndet före sammanfogningen.

Innan du sammanfogar bör du checka in eller stash:a lokala ändringar: sammanfogningen bygger om arbetsträdet utifrån resultatet och skriver över oincheckade ändringar i spårade filer ([#2](https://github.com/inline0/pitmaster/issues/2)).

## Snabbspolade sammanfogningar

När det aktuella HEAD är en anfader till målgrenen utför Pitmaster en snabbspolad sammanfogning: den flyttar helt enkelt HEAD till målincheckningen utan att skapa en sammanfogningsincheckning.

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

Det omvända fallet identifieras ännu inte: när en gren sammanfogas som HEAD redan innehåller skapas en ny sammanfogningsincheckning med ett oförändrat träd i stället för att rapportera "Already up to date" ([#6](https://github.com/inline0/pitmaster/issues/6)).

## Trevägssammanfogning

När grenar har gått isär utför Pitmaster en tredelad sammanfogning:

1. Hitta sammanfogningsbasen (den närmaste gemensamma anfadern)
2. Jämför basen med vår och deras på trädnivå
3. Utför en sammanfogning på innehållsnivå för varje fil som ändrats i båda grenarna
4. Skapa en sammanfogningsincheckning med två föräldrar

```
Before:              After merge:

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

## Sammanfogningsbas

Sammanfogningsbasen är den senaste gemensamma anfadern till två incheckningar. Pitmaster hittar den genom att gå igenom incheckningsgrafen. Om det finns flera sammanfogningsbaser (korsande historik) sammanfogar `merge()` dem först och använder resultatet som bas.

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

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

För direkt åtkomst till algoritmen `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);
```

## Kontroll av grensammanfogning

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

## Konfliktmarkörer

När en fil har ändrats i båda grenarna och ändringarna överlappar skapar Pitmaster standardmässiga konfliktmarkörer. `merge()` märker upp sidorna som `HEAD` och namnet på den sammanfogade grenen:

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

Klassen `ConflictMarker` omsluter två versioner med markörer:

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

## Tredelad sammanfogning på innehållsnivå

Klassen `ThreeWayMerge` sammanfogar blob-innehåll (inte filer):

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

Den tar tre strängar (basversionen, vår version och deras version) plus valfria etiketter och en konfliktstil (`'merge'` som standard, eller `'diff3'` för att ta med basavsnittet).

## Sammanfogningsstrategier

### Rekursiv sammanfogning

Standardstrategin (`$repo->merge($branch)`) hanterar korsande sammanfogningshistorik med flera sammanfogningsbaser. CLI accepterar också `-s ort` och `-s recursive` för den.

### Ours-sammanfogning

Skapar en sammanfogningsincheckning som behåller HEAD:s träd oförändrat. Användbart för att bevara grenens historik utan att införliva ändringar.

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

### Octopus-sammanfogning

Sammanfogar två eller fler grenar till en enda sammanfogningsincheckning. Om någon gren hamnar i konflikt returneras ett orent resultat utan att sammanfogningsstatus skrivs eller en incheckning skapas.

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

Klasserna `RecursiveMerge`, `OursMerge` och `OctopusMerge` i `Pitmaster\Merge` är hjälpfunktioner på innehållsnivå; `Repository` implementerar själv strategierna ovan.

## Rerere (återanvändning av sparad konfliktlösning)

Pitmaster innehåller en fristående `Rerere`-klass som lagrar konfliktlösningar i gits `rr-cache`-layout:

```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()` anropar den inte: konfliktlösningar registreras och återanvänds bara när din kod gör det. `isEnabled()` letar efter den bokstavliga texten `rerere.enabled = true` i `.git/config` och känner inte igen avsnittet `[rerere]` som `git config rerere.enabled true` skriver ([#20](https://github.com/inline0/pitmaster/issues/20)).

## Sammanfogningsflöde på trädnivå

Hela sammanfogningsprocessen:

1. `MergeBase::findAll()` hittar de gemensamma anfäderna
2. Basens, vår och deras träd jämförs sökväg för sökväg
3. För filer som bara ändrats i en gren: ta den ändringen
4. För filer som ändrats i båda grenarna:
   - Om båda ändrats på samma sätt: ta endera (de är överens)
   - Om ändringarna skiljer sig: kör `ThreeWayMerge::merge()` på innehållet
5. Om alla sammanfogningar är konfliktfria: bygg det sammanfogade trädet och skapa en sammanfogningsincheckning
6. Vid konflikter: returnera `MergeResult` med `clean = false` och konfliktsökvägarna

## Användning av CLI

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

Utdata vid lyckat resultat:
```
Merge successful.
```

Utdata vid konflikt:
```
CONFLICT in: src/File.php, src/Other.php
```
