
# Üç Yönlü Birleştirme

Üç yönlü birleştirme, iki değişiklik kümesini ortak bir ataya göre karşılaştırır ve bunları tek bir sonuçta birleştirir. merql bu algoritmayı dosya satırları yerine veritabanı satırlarına uygular.

```php
use Merql\Merge\ThreeWayMerge;

$merge = new ThreeWayMerge();
$result = $merge->merge($base, $ours, $theirs);

echo $result->operationCount(); // resolved operations
echo $result->conflictCount();  // unresolved conflicts
```

## Üç durum

Her birleştirme için tam olarak üç anlık görüntü gerekir:

- **Base** -- her iki dalın ayrıldığı noktadaki veritabanı durumu.
- **Ours** -- değişikliklerinden sonraki bir dal; örneğin düzenlenmiş bir korumalı alan kopyası.
- **Theirs** -- değişikliklerinden sonraki diğer dal; örneğin çalışmaya devam eden canlı veritabanı.

Ours ve theirs, ilgili dalı barındıran veritabanından alınmış olmalıdır. Birleştirme kuralları her iki tarafı aynı şekilde ele alır; adlar her işlemin `source` değerini, çakışma türlerinin nasıl adlandırılacağını (`update_delete`, ours güncellenip theirs silindiği anlamına gelir) ve hangi tarafın `ConflictPolicy::OursWins` ile `TheirsWins` tercih ettiğini belirler.

```
         Base (snapshot at fork time)
        /                              \
   Ours (our changes)                   Theirs (their changes)
        \                              /
         --------- MERGE ----------
                     |
              Merged result
              + conflicts (if any)
```

Ortak bir base olmadan "eklenen" ile "değişmeden kalan"ı ayırt edemezsiniz. İki yönlü karşılaştırma, A tarafında bir değer, B tarafında olmadığını görür; ancak A'nın bunu eklediğini mi yoksa B'nin sildiğini mi belirleyemez. Bu soruyu base yanıtlar.

## Değişiklik kümeleri nasıl hesaplanır

`Differ`, iki değişiklik kümesi oluşturmak için her anlık görüntüyü base ile karşılaştırır. Her değişiklik kümesi üç tür işlem içerir:

| Base | Geçerli | İşlem |
|---|---|---|
| Satır var | Satır var, parmak izi aynı | Değişiklik yok |
| Satır var | Satır var, parmak izi farklı | **UPDATE** (sütun bazında fark) |
| Satır var | Satır yok | **DELETE** |
| Satır yok | Satır var | **INSERT** |

Parmak izleri (SHA-256 normalleştirilmiş satır içeriğinin karmaları) hızlı bir yol sağlar. İki parmak izi eşleşirse satır değişmemiştir ve sütun düzeyinde karşılaştırma gerekmez.

```php
use Merql\Diff\Differ;

$differ = new Differ();
$oursChangeset = $differ->diff($base, $ours);
$theirsChangeset = $differ->diff($base, $theirs);
```

## Birleştirme kuralları

İki değişiklik kümesi daha sonra işlem işlem birleştirilir. Bu tablo, her birleşim için sonucu tanımlar:

| Ours | Theirs | Sonuç |
|---|---|---|
| Değişiklik yok | Değişiklik yok | Base'i koru |
| Değişiklik yok | Güncellendi | Theirs'ü kabul et |
| Güncellendi | Değişiklik yok | Ours'u kabul et |
| Güncellendi (aynı değer) | Güncellendi (aynı değer) | Kabul et (ikisi de aynı fikirde) |
| Güncellendi (farklı değer) | Güncellendi (farklı değer) | **Çakışma** |
| Değişiklik yok | Silindi | Silmeyi kabul et |
| Silindi | Değişiklik yok | Silmeyi kabul et |
| Silindi | Silindi | Silmeyi kabul et (ikisi de aynı fikirde) |
| Güncellendi | Silindi | **Çakışma** |
| Silindi | Güncellendi | **Çakışma** |
| Eklendi (yalnızca ours) | -- | Ekleme işlemini kabul et |
| -- | Eklendi (yalnızca theirs) | Ekleme işlemini kabul et |
| Eklendi (aynı PK) | Eklendi (aynı PK) | **Çakışma** |

Her iki taraf da aynı satırı güncellediğinde merql hemen çakışma ilan etmez. Sütun düzeyinde birleştirme aşamasına geçerek her sütunu bağımsız karşılaştırır. Ayrıntılar için [Sütun Düzeyinde Birleştirme](https://merql.inline0.dev/tr/docs/merge/column-level) sayfasına bakın.

## Facade kullanımı

`Merql` facade, diske kalıcı olarak kaydedilmiş adlandırılmış anlık görüntüler üzerinde çalışır. Anlık görüntü almadan önce, her durumu barındıran veritabanıyla `Merql::init()` çağrısını yapın:

```php
use Merql\Connection;
use Merql\Merql;

$live    = Connection::sqlite('/data/live.sqlite');
$sandbox = Connection::sqlite('/data/sandbox.sqlite');

Merql::init($live);
Merql::snapshot('base');      // before the sandbox is copied from live

// ... copy live.sqlite to sandbox.sqlite, then both databases change ...

Merql::init($sandbox);
Merql::snapshot('ours');
Merql::init($live);
Merql::snapshot('theirs');

$result = Merql::merge('base', 'ours', 'theirs');
```

Üç anlık görüntüyü de tek bir veritabanından art arda almayın. Böyle yaparsanız theirs, ours değişikliklerini de içerir; bu nedenle ours'un eklediği her satır her iki tarafta da eklenmiş görünür ve `insert_insert` çakışması olarak bildirilir.

`Merql::merge()`, `Merql::patch()` ve `Merql::plan()`, `ThreeWayMerge` olmadan `CellMergeConfig` oluşturur; bu nedenle yalnızca sütun düzeyinde birleştirme yaparlar. Hücre düzeyinde birleştirme için anlık görüntüleri yükleyip aşağıdaki gibi sınıfı doğrudan kullanın.

## Sınıfları doğrudan kullanma

Daha fazla denetim için bileşenleri kendiniz örnekleyin. `Snapshotter::capture()` hiçbir şeyi kalıcı olarak kaydetmez; bu nedenle anlık görüntüleri bellekte tutun veya `SnapshotStore::save()` ile kaydedin:

```php
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;
use Merql\Snapshot\Snapshotter;
use Merql\Snapshot\SnapshotStore;

$base   = (new Snapshotter($live))->capture('base');
// ... copy live to the sandbox, then both databases change ...
$ours   = (new Snapshotter($sandbox))->capture('ours');
$theirs = (new Snapshotter($live))->capture('theirs');

$merge = new ThreeWayMerge();
$result = $merge->merge($base, $ours, $theirs);

// Snapshots saved earlier, merged with cell-level merge for TEXT and JSON columns.
$merge = new ThreeWayMerge(CellMergeConfig::auto());
$result = $merge->merge(
    SnapshotStore::load('base'),
    SnapshotStore::load('ours'),
    SnapshotStore::load('theirs'),
);
```

## Yama kısayolu

Yalnızca bir tarafta değişiklik olduğunda (eşzamanlı değişiklik yoksa) `patch()` kullanın. Bu, ours'un base'e eşit olduğu iki yönlü bir birleştirmedir; dolayısıyla çakışma mümkün değildir:

```php
$result = $merge->patch($base, $changes);
// Always clean: ours is identical to base.
```

Facade üzerinden:

```php
$result = Merql::patch('base', 'changes');
```

`patch()`, `merge($base, $base, $changes)` ile eşdeğerdir. Ours base'den hiç sapmadığı için theirs'teki her değişiklik çakışma olmadan kabul edilir.

## Şema uyuşmazlığını algılama

Anlık görüntüler arasında bir tabloya sütun eklenmiş veya tablodan sütun kaldırılmışsa birleştirme devam eder, ancak uyuşmazlıkları kaydeder. Değişen sütun türleri karşılaştırılmaz; yeniden adlandırılan bir sütun, kaldırılmış bir sütun ve eklenmiş bir sütun olarak görünür; bkz. [Şema Doğrulama](https://merql.inline0.dev/tr/docs/advanced/schema).

```php
$result = $merge->merge($base, $ours, $theirs);

if ($result->hasSchemaMismatches()) {
    foreach ($result->schemaMismatches() as $mismatch) {
        echo $mismatch->getMessage() . "\n";
    }
}
```

merql şemaları otomatik olarak taşımaz. Şema değişikliklerinden çağıran taraf sorumludur. Birleştirme bunları bildirir, böylece nasıl devam edeceğinize karar verebilirsiniz.

## MergeResult

Sonuç nesnesi ihtiyacınız olan her şeyi içerir:

```php
$result->isClean();            // true if no conflicts
$result->operations();         // list of MergeOperation objects
$result->conflicts();          // list of Conflict objects
$result->operationCount();     // number of resolved operations
$result->conflictCount();      // number of unresolved conflicts
$result->hasSchemaMismatches(); // true if schemas differ
$result->baseSnapshot();       // the base snapshot used for the merge
```

Her `MergeOperation` bir türe (`insert`, `update` veya `delete`), tablo adına, satır anahtarına, sütun değerlerine ve kaynağa (`ours`, `theirs` veya `merged`) sahiptir. `merged`, her iki tarafın da bir satırı güncellediğini (sütun sütun birleştirilmiştir) veya sildiğini belirtir.

## Birleştirme sonucu nerede uygulanır

Birleştirme sonucu, base durumunu birleştirilmiş duruma nasıl dönüştüreceğinizi açıklar. İşlemleri her iki tarafın değişikliklerini içerir: ours'un eklediği bir satır da theirs'ün eklediği bir satır da ekleme olarak görünür.

- `Merql::apply()` (veya `Applier`), bağlı veritabanında her işlemi yürütür. Base'i hâlâ barındıran bir veritabanına, örneğin base durumunun yeni bir kopyasına sorunsuz uygulanır. Bir tarafın değişikliklerini zaten içeren bir veritabanında, mevcut bir satırı ekleme girişimi başarısız olur ve işlem geri alınır.
- Canlı ortamı güncellemek için korumalı alan düzenlemelerini canlıya taşımak gibi, zaten theirs'ü barındıran bir veritabanına ours'u aktarmak için yalnızca o veritabanında bulunmayan işlemleri uygulayın: kaynağı `ours` olan işlemleri ve `merged` güncellemelerini. Bunları seçmek için bir [birleştirme planı](https://merql.inline0.dev/tr/docs/merge/plans) kullanın ve canlı satır önkoşullarıyla yazmak için [Korumalı Uygulama](https://merql.inline0.dev/tr/docs/apply/guarded) özelliğini kullanın.
