
# Mesclagem

Pitmaster realiza mesclagens de branches com uma mesclagem de três vias, como `git merge`. Detecta oportunidades de avanço rápido, calcula bases de mesclagem, realiza mesclagens no nível da árvore e do conteúdo e gera marcadores de conflito padrão quando há conflitos nos arquivos.

## Mesclagem básica

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

A classe `MergeResult` é um objeto de valor somente leitura:

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

Quando a mesclagem para por causa de conflitos, o estado do conflito é gravado no índice e na árvore de trabalho. Resolva os arquivos, `add()` e chame `$repo->mergeContinue()`, ou chame `$repo->mergeAbort()` para restaurar o estado anterior à mesclagem.

Antes de mesclar, faça commit ou guarde as alterações locais: a mesclagem recria a árvore de trabalho a partir do resultado e sobrescreve alterações não commitadas em arquivos rastreados ([#2](https://github.com/inline0/pitmaster/issues/2)).

## Mesclagens por avanço rápido

Quando o HEAD atual é um ancestral da branch de destino, Pitmaster realiza uma mesclagem por avanço rápido: simplesmente move o HEAD para o commit de destino sem criar um commit de mesclagem.

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

O caso inverso ainda não é detectado: mesclar uma branch que o HEAD já contém cria um novo commit de mesclagem com uma árvore inalterada, em vez de informar "Already up to date" ([#6](https://github.com/inline0/pitmaster/issues/6)).

## Mesclagem de três vias

Quando as branches divergiram, Pitmaster realiza uma mesclagem de três vias:

1. Encontrar a base de mesclagem (ancestral comum mais próximo)
2. Fazer diff da base até a nossa versão e da base até a deles no nível da árvore
3. Para cada arquivo alterado em ambas as branches, realizar a mesclagem no nível do conteúdo
4. Criar um commit de mesclagem com dois pais

```
Before:              After merge:

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

## Base de mesclagem

A base de mesclagem é o ancestral comum mais recente de dois commits. Pitmaster a encontra percorrendo o grafo de commits. Quando há várias bases de mesclagem (histórico cruzado), `merge()` as mescla primeiro e usa o resultado como base.

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

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

Para acessar diretamente o algoritmo de `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);
```

## Verificação de mesclagem de branches

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

## Marcadores de conflito

Quando um arquivo é modificado em ambas as branches e as alterações se sobrepõem, Pitmaster gera marcadores de conflito padrão. `merge()` identifica os lados como `HEAD` e o nome da branch mesclada:

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

A classe `ConflictMarker` envolve duas versões em marcadores:

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

## Mesclagem de três vias no nível do conteúdo

A classe `ThreeWayMerge` mescla o conteúdo de blobs (não arquivos):

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

Ela recebe três strings (a versão base, a nossa versão e a versão deles), além de rótulos opcionais e um estilo de conflito (`'merge'` por padrão ou `'diff3'` para incluir a seção da base).

## Estratégias de mesclagem

### Mesclagem recursiva

A estratégia padrão (`$repo->merge($branch)`) trata históricos de mesclagem cruzada com várias bases de mesclagem. CLI também aceita `-s ort` e `-s recursive` para essa estratégia.

### Mesclagem nossa

Registra um commit de mesclagem que mantém inalterada a árvore do HEAD. Útil para manter o histórico da branch sem incorporar alterações.

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

### Mesclagem octopus

Mescla duas ou mais branches em um único commit de mesclagem. Se houver conflito em qualquer branch, retorna um resultado não limpo sem gravar o estado da mesclagem nem criar um commit.

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

As classes `RecursiveMerge`, `OursMerge` e `OctopusMerge` em `Pitmaster\Merge` são auxiliares para mesclagem no nível do conteúdo; `Repository` implementa as estratégias acima por conta própria.

## Rerere (reutilizar resolução registrada)

Pitmaster inclui uma classe `Rerere` independente que armazena resoluções no layout de `rr-cache` de 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()` não a chama: as resoluções só são registradas e reaplicadas quando seu código faz isso. `isEnabled()` procura o texto literal `rerere.enabled = true` em `.git/config` e não reconhece a seção `[rerere]` que `git config rerere.enabled true` grava ([#20](https://github.com/inline0/pitmaster/issues/20)).

## Fluxo de mesclagem no nível da árvore

O processo completo de mesclagem:

1. `MergeBase::findAll()` localiza os ancestrais comuns
2. As árvores da base, nossa e deles são comparadas caminho por caminho
3. Para arquivos alterados em apenas uma branch: aplicar essa alteração
4. Para arquivos alterados em ambas as branches:
   - Se ambas alteraram da mesma forma: aplicar qualquer uma (são iguais)
   - Se as alterações forem diferentes: executar `ThreeWayMerge::merge()` no conteúdo
5. Se todas as mesclagens forem limpas: criar a árvore mesclada e criar um commit de mesclagem
6. Se houver conflitos: retornar `MergeResult` com `clean = false` e os caminhos em conflito

## Uso de CLI

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

Saída em caso de sucesso:
```
Merge successful.
```

Saída em caso de conflito:
```
CONFLICT in: src/File.php, src/Other.php
```
