Ugrás a tartalomhoz

Bevezetés

A merql egy tiszta PHP-könyvtár, amely háromutas egyesítést végez az adatbázis állapotán. Pillanatképeket készít a táblákról, kiszámítja a pillanatképek közötti módosításkészleteket, egy közös alap alapján egyesíti a két módosításkészletet, és oszlopszinten észleli az ütközéseket. Ugyanazt az algoritmust alkalmazza sorokra és oszlopokra, amelyet a git a forrásfájlok sorain használ.

Nincsenek külső eszközök. A MySQL és a SQLite támogatása cserélhető kapcsolatadaptereken és dialektus-illesztőprogramokon keresztül történik.

Gyors példa

Az egyesítéshez ugyanazon adatok három állapota kell: az alap, amelyből mindkét példány kiindult, valamint a két példány a külön-külön végzett módosítások után. Ebben az esetben egy tesztkörnyezetet másoltak az éles adatbázisból, és azóta mindkettőt módosították.

PHP
use Merql\Connection;
use Merql\Merql;

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

// Base: live at the moment the sandbox was copied from it.
Merql::init($live);
Merql::snapshot('base');

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

// Ours: the sandbox with our edits. Theirs: live with its own changes.
Merql::init($sandbox);
Merql::snapshot('ours');
Merql::init($live);
Merql::snapshot('theirs');

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

if ($result->isClean()) {
    foreach ($result->operations() as $operation) {
        echo "{$operation->type} {$operation->table} #{$operation->rowKey} ({$operation->source})\n";
    }
} else {
    echo "Conflicts: {$result->conflictCount()}\n";
}

Minden pillanatképet abból az adatbázisból kell rögzíteni, amely az adott állapotot tartalmazza. Ha egymás után mindhármat ugyanabból az adatbázisból veszi, az nem két különvált példány állapotát írja le: a másik fél állapota már tartalmazná a saját módosításait, és minden általunk beszúrt sor insert_insert ütközésként jelenne meg.

Az eredmény felsorolja az alapállapotot az egyesített állapottá alakító műveleteket mindkét oldalról, és mindegyikhez hozzárendeli a forrását (ours, theirs vagy merged). Ha a tesztkörnyezet módosításait az éles adatbázisba szeretné átvinni, alkalmazza azokat a műveleteket, amelyek még hiányoznak az éles adatbázisból a Feltételes alkalmazás segítségével.

Vagy a CLI használatával, amely minden snapshot esetén a MERQL_DB_DSN által megadott adatbázishoz csatlakozik:

Shell
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot base
# ... copy live.sqlite to sandbox.sqlite, then both databases change ...
MERQL_DB_DSN="sqlite:/data/sandbox.sqlite" vendor/bin/merql snapshot ours
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot theirs

vendor/bin/merql merge base ours theirs --dry-run

Miért a merql

A legtöbb állapotot összehasonlító adatbázis-eszköz sorszinten működik: ha egy sor bármely oszlopa eltér a két verzió között, az egész sort ütközésként jelöli meg. Ez téves ütközéseket okoz, ha két ember ugyanazon sor különböző oszlopait szerkeszti.

A merql oszlopszinten végez egyesítést. Ha az egyik fél a title-t, a másik pedig a status-t módosította, a változások ütközés nélkül egyesíthetők. A rendszer csak akkor jelez ütközést, ha mindkét fél ugyanazt az oszlopot eltérő értékre módosítja.

A TEXT és JSON oszlopoknál a merql egy szinttel mélyebbre is mehet, és cellaszintű egyesítést végezhet. A szövegoszlop különböző sorait érintő két módosítás, illetve az JSON oszlop különböző kulcsait érintő két módosítás ugyanazzal a háromutas algoritmussal tisztán egyesíthető. A cellaszintű egyesítés választható: adjon át egy CellMergeConfig értéket a(z) ThreeWayMerge számára. A Merql homlokzat és a CLI csak oszlopszinten egyesít. Lásd: Cellaszintű egyesítés.

Az egyesítési modell

Kód
         Base (snapshot at fork time)
        /                              \
   Ours (one copy's changes)            Theirs (the other copy's changes)
        \                              /
         --------- MERGE ----------
                     |
              Merged result
              + conflicts (if any)

Három állapot, akárcsak a gitben. A base a közös ős. Az ours és a theirs a szétválás után létrejött két másolat, mindegyiket a saját adatbázisa rögzíti. Az egyesítési szabályok egyformán kezelik mindkét oldalt. A nevek megjelennek az egyes műveletek source értékében, az ütközéstípusokban (az update_delete azt jelenti, hogy az ours frissített, a theirs pedig törölt), valamint a OursWins és TheirsWins feloldási szabályzatokban. Közös alap nélkül nem lehet megkülönböztetni a „hozzáadott” és a „változatlan” állapotot.

Az egyesítés önmagában nem ír semmit. Műveletei a base állapotot alakítják át az egyesített állapottá, ezért az Merql::apply() csak olyan adatbázison futtatja le mindegyiket ütközésmentesen, amely még a base állapotot tartalmazza. Ha az egyik oldal módosításait egy olyan adatbázisba szeretné átvinni, amely már a másik oldal állapotát tartalmazza, például a sandboxban végzett szerkesztéseket éles környezetbe emelné, csak a hiányzó műveleteket alkalmazza; lásd: Védett alkalmazás.

Követelmények

  • PHP 8.2 vagy újabb.
  • ext-mbstring és ext-zlib, amelyeket az pitmaster/pitmaster függőség igényel a szövegkülönbségek kiszámításához.
  • Az Ön által használt adapterhez szükséges adatbázis-bővítmény: ext-pdo ext-pdo_sqlite vagy ext-pdo_mysql használatával, illetve ext-mysqli. A merql composer.json csak a ext-pdo és ext-mysqli használatát javasolja, ezért az Composer nem ellenőrzi, hogy ezek telepítve vannak-e.
  • MySQL vagy SQLite adatbázis. Más motorokhoz egyéni illesztőprogram szükséges.

Ami nem tartozik ide

A merql nem sémamigrációs eszköz. Nem replikál adatbázisokat és nem szinkronizálja őket valós időben. Egyetlen konkrét problémát old meg: három adatbázis-állapotból létrehoz egy negyedik, egyesített állapotot, és azonosítja az ütközéseket.

Dokumentáció