Siirry sisältöön

Johdanto

merql on puhdas PHP-kirjasto, joka tekee tietokannan tilalle kolmisuuntaisia yhdistämisiä. Se tallentaa tauluista tilannevedoksia, laskee niiden väliset muutossarjat, yhdistää kaksi muutosjoukkoa yhteiseen lähtötilaan nähden ja havaitsee ristiriidat saraketasolla. Käytössä on sama algoritmi kuin gitin lähdetiedostoissa, mutta sitä sovelletaan tietokannan riveihin ja sarakkeisiin tekstirivien sijaan.

Ei ulkoisia työkaluja. Tukee MySQL- ja SQLite-tietokantoja liitettävien yhteyssovittimien ja murreajurien kautta.

Pikaesimerkki

Yhdistämiseen tarvitaan kolme saman datan tilaa: lähtötila, josta molemmat kopiot aloittivat, sekä kaksi kopiota niiden itsenäisten muutosten jälkeen. Tässä testiympäristö kopioitiin tuotantotietokannasta, ja molempia on sittemmin muokattu.

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";
}

Kukin tilannevedos otetaan tietokannasta, jossa kyseinen tila on. Kaikkien kolmen ottaminen samasta tietokannasta peräkkäin ei kuvaa kahta erkaantunutta kopiota: theirs sisältäisi jo ours-muutokset, ja jokainen ours-puolen lisäämä rivi ilmoitettaisiin insert_insert-ristiriitana.

Tulos luettelee toiminnot, jotka muuttavat basen yhdistetyksi tilaksi, ja sisältää molempien puolten muutokset. Kukin toiminto on merkitty lähteellään (ours, theirs tai merged). Jos haluat kirjoittaa testiympäristön muutokset tuotantoon, käytä komentoa Suojattu käyttö ja sovella vain toimintoja, joita tuotantoympäristössä ei vielä ole.

Tai käytä CLI-ohjelmaa, joka yhdistää tietokantaan, joka on määritetty kullekin snapshot-arvolle kohteessa MERQL_DB_DSN:

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

Miksi merql

Useimmat tietokantatyökalut vertaavat tiloja rivitasolla: jos yksikin rivin sarake eroaa kahden version välillä, koko rivi merkitään ristiriidaksi. Näin syntyy vääriä ristiriitoja, kun kaksi henkilöä muokkaa saman rivin eri sarakkeita.

merql yhdistää muutokset saraketasolla. Jos toinen puoli muutti arvoa title ja toinen arvoa status, muutokset yhdistyvät ongelmitta ilman ristiriitaa. Ristiriita syntyy vain, kun molemmat puolet muuttavat saman sarakkeen eri arvoon.

TEXT- ja JSON-sarakkeissa merql voi yhdistää yhtä tasoa syvemmältä solutasolla. Tekstisarakkeen eri riveihin tai JSON-sarakkeen eri avaimiin tehdyt muutokset voidaan yhdistää ongelmitta samalla kolmen osapuolen algoritmilla. Solutason yhdistäminen on valinnainen: välitä CellMergeConfig kohteelle ThreeWayMerge. Merql-julkisivu ja CLI yhdistävät vain saraketasolla. Katso Solutason yhdistäminen.

Yhdistämismalli

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

Kolme tilaa, kuten gitissä. Base on yhteinen edeltäjä. Ours ja theirs ovat kaksi kopiota niiden erkaantumisen jälkeen; kumpikin tallennetaan omasta tietokannastaan. Yhdistämissäännöt kohtelevat molempia puolia samalla tavalla. Nimet näkyvät kunkin toiminnon source-kentässä, ristiriitatyypeissä (update_delete tarkoittaa, että ours päivitti ja theirs poisti) sekä OursWins- ja TheirsWins-ratkaisukäytännöissä. Ilman yhteistä lähtötilaa et voi erottaa lisäystä muuttumattomasta.

Yhdistäminen ei itsessään kirjoita mitään. Sen toiminnot muuntavat basen yhdistetyksi tilaksi, joten Merql::apply() suorittaa ne kaikki ongelmitta vain tietokannassa, jossa on yhä base-tila. Jos haluat tuoda toisen puolen muutokset tietokantaan, jossa on jo toisen puolen muutokset, esimerkiksi siirtää testiympäristön muokkaukset tuotantoon, käytä vain puuttuvia toimintoja; katso Suojattu käyttö.

Vaatimukset

  • PHP 8.2 tai uudempi.
  • ext-mbstring ja ext-zlib, joita tekstierot tuottava pitmaster/pitmaster-riippuvuus edellyttää.
  • Käyttämääsi sovitinta vastaava tietokantalaajennus: ext-pdo sekä ext-pdo_sqlite tai ext-pdo_mysql, tai ext-mysqli. merqlin composer.json ainoastaan ehdottaa ext-pdo- ja ext-mysqli-laajennuksia, joten Composer ei tarkista niiden olemassaoloa.
  • MySQL- tai SQLite-tietokanta. Muut tietokantamoottorit tarvitsevat mukautetun ajurin.

Mitä se ei ole

merql ei ole tietokantakaavion siirtotyökalu. Se ei repliko tietokantoja eikä synkronoi niitä reaaliajassa. Se ratkaisee yhden rajatun ongelman: kun käytössä on kolme tietokannan tilaa, tuottaa neljännen, yhdistetyn tilan ja tunnistaa ristiriidat.

Dokumentaatio