İçeriğe geç

Üç 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.

Kod
         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 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.

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ı kullanın ve canlı satır önkoşullarıyla yazmak için Korumalı Uygulama özelliğini kullanın.