Preskočiť na obsah

Zlučovanie na úrovni buniek

Zlučovanie na úrovni stĺpcov zisťuje, či obe strany zmenili ten istý stĺpec. Zlučovanie na úrovni buniek ide hlbšie a spája obsah daného stĺpca. Dvaja ľudia môžu bez konfliktu zlúčiť úpravy rôznych riadkov poľa TEXT alebo rôznych kľúčov objektu JSON.

PHP
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;

$config = CellMergeConfig::auto();
$merge = new ThreeWayMerge($config);
$result = $merge->merge($base, $ours, $theirs);

Zapnutie zlučovania na úrovni buniek

Zlučovanie na úrovni buniek je voliteľné. Spustí sa iba v ThreeWayMerge vytvorenom s CellMergeConfig. Bez neho sa každý stĺpec, ktorý obe strany zmenili na rôzne hodnoty, považuje za konflikt update_update.

Fasáda Merql neprijíma konfiguráciu: Merql::merge(), Merql::patch() a Merql::plan() vytvárajú new ThreeWayMerge() bez nej a príkaz merge v CLI používa Merql::merge(). Vždy vykonávajú zlúčenie na úrovni stĺpcov (#7).

Ak chcete zlúčiť snímky uložené fasádou alebo príkazom CLI na úrovni buniek, načítajte ich a sami zavolajte ThreeWayMerge. Výsledok je bežný MergeResult, takže ho fasáda stále môže použiť, a MergePlanBuilder z neho vytvorí plán zlúčenia:

PHP
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;
use Merql\Merql;
use Merql\Plan\MergePlanBuilder;
use Merql\Snapshot\SnapshotStore;

$base   = SnapshotStore::load('base');
$ours   = SnapshotStore::load('ours');
$theirs = SnapshotStore::load('theirs');

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

$plan = (new MergePlanBuilder())->build('plan-1', $base, $ours, $theirs, $result);

Zlučovače buniek sa spúšťajú iba pre stĺpce, ktoré zmenili obe strany. Ak stĺpec zmenila iba jedna strana, jeho hodnota sa prevezme bez úprav.

CellMergeConfig

CellMergeConfig mapuje stĺpce alebo typy stĺpcov na implementácie zlučovačov buniek. Továreň auto() poskytuje vhodné predvolené nastavenia:

PHP
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\JsonCellMerger;
use Merql\CellMerge\TextCellMerger;

// Auto: column types containing "text" (TEXT, MEDIUMTEXT, LONGTEXT, ...) use
// TextCellMerger, column types containing "json" use JsonCellMerger.
$config = CellMergeConfig::auto();

// Custom: assign mergers to specific columns.
$config = (new CellMergeConfig())
    ->forColumn('posts.content', new TextCellMerger())
    ->forColumn('settings', new JsonCellMerger())
    ->forType('json', new JsonCellMerger());

Priorita výberu zlučovača:

  1. Úplný názov stĺpca (table.column).
  2. Názov stĺpca bez kvalifikátora (column).
  3. Zhoda so vzorom typu stĺpca (bez rozlišovania veľkých a malých písmen str_contains).
  4. Predvolené nastavenie: OpaqueCellMerger (pri každom rozdiele vždy nahlási konflikt).

TextCellMerger

Zlučuje viacriadkový text pomocou Myersovho rozdielového algoritmu, ktorý git používa aj pre obsah súborov. Každý riadok sa považuje za jednotku a zmeny v rôznych riadkoch sa zlúčia bez konfliktu.

PHP
use Merql\CellMerge\TextCellMerger;

$merger = new TextCellMerger();

Príklad: čisté zlúčenie textu

Kód
Base:    "line one\nline two\nline three"
Ours:    "LINE ONE\nline two\nline three"    // changed line 1
Theirs:  "line one\nline two\nLINE THREE"    // changed line 3

Upravili sa rôzne riadky. Výsledkom zlúčenia je "LINE ONE\nline two\nLINE THREE" bez konfliktu.

Príklad: konflikt v texte

Kód
Base:    "line one\nline two"
Ours:    "changed by us\nline two"     // changed line 1
Theirs:  "changed by them\nline two"   // also changed line 1

Obe strany zmenili ten istý riadok na rôzne hodnoty. Zlučovač vráti výsledok s konfliktom. Zlúčený obsah zahŕňa značky konfliktu podobné tým v git.

Ako to funguje

TextCellMerger využíva ThreeWayMerge::merge() z pitmaster, ktorý vypočíta Myersov rozdiel medzi base a každou stranou a potom spojí oba skripty úprav. Ak sa úpravy prekrývajú v tej istej oblasti riadka, nahlási konflikt.

JsonCellMerger

Zlučuje objekty JSON porovnávaním jednotlivých kľúčov najvyššej úrovne. Každý kľúč sa zlúči podľa štandardných trojstranných pravidiel.

PHP
use Merql\CellMerge\JsonCellMerger;

$merger = new JsonCellMerger();

Príklad: čisté zlúčenie JSON

JSON
// Base
{"name": "Alice", "role": "editor", "active": true}

// Ours: changed "role"
{"name": "Alice", "role": "admin", "active": true}

// Theirs: changed "name"
{"name": "Bob", "role": "editor", "active": true}

Zmenili sa rôzne kľúče. Výsledok zlúčenia:

JSON
{"name": "Bob", "role": "admin", "active": true}

Príklad: konflikt JSON

JSON
// Base
{"color": "red"}

// Ours
{"color": "blue"}

// Theirs
{"color": "green"}

Obe strany zmenili kľúč color na rôzne hodnoty. Ide o konflikt. Zlučovač predvolene uprednostní ours a nahlási jeden konflikt.

Pravidlá na úrovni kľúčov

Base Ours Theirs Výsledok
Kľúč nezmenený Kľúč nezmenený Prijať base
Kľúč nezmenený Kľúč zmenený Prijať theirs
Kľúč zmenený Kľúč nezmenený Prijať ours
Kľúč zmenený (rovnako) Kľúč zmenený (rovnako) Prijať (zhoda)
Kľúč zmenený (odlišne) Kľúč zmenený (odlišne) Konflikt (predvolene: ours)
Kľúč existuje Kľúč existuje Kľúč odstránený Prijať odstránenie
Kľúč existuje Kľúč odstránený Kľúč existuje Prijať odstránenie
Kľúč chýba Kľúč pridaný Kľúč chýba Prijať pridanie
Kľúč chýba Kľúč chýba Kľúč pridaný Prijať pridanie

Vnorené objekty sa porovnávajú ako nepriehľadné reťazce JSON, nie rekurzívne. Ak sa vnorený objekt líši, porovná sa celá hodnota daného kľúča, nie jeho podkľúče.

Požiadavky

Všetky tri hodnoty musia byť platné objekty alebo polia JSON. Ak niektorá hodnota nie je platná JSON alebo je skalárnou hodnotou JSON (reťazec, číslo, logická hodnota), zlučovač prejde na konflikt.

OpaqueCellMerger

Predvolený zlučovač, ak nie je nakonfigurovaná žiadna stratégia zlučovania buniek. Hodnotu stĺpca považuje za nepriehľadný blok a vždy nahlási konflikt, keď sa hodnoty oboch strán líšia.

PHP
use Merql\CellMerge\OpaqueCellMerger;

$merger = new OpaqueCellMerger();
$result = $merger->merge($base, $ours, $theirs);
// $result->clean is always false when $ours !== $theirs

CellMergeResult

Všetky zlučovače buniek vracajú CellMergeResult:

PHP
$result = $merger->merge($base, $ours, $theirs);

$result->clean;     // bool: true if merge resolved cleanly
$result->value;     // mixed: the merged value (or ours on conflict)
$result->conflicts; // int: number of conflicts within the cell

Metódy továrne:

PHP
CellMergeResult::resolved($value);           // clean merge
CellMergeResult::conflict($oursValue, $n);   // n conflicts, defaults to ours

Vlastné zlučovače buniek

Ak chcete pridať vlastnú stratégiu zlúčenia, implementujte rozhranie CellMerger:

PHP
use Merql\CellMerge\CellMerger;
use Merql\CellMerge\CellMergeResult;

class YamlCellMerger implements CellMerger
{
    public function merge(mixed $base, mixed $ours, mixed $theirs): CellMergeResult
    {
        // Parse YAML, merge keys, return result.
        $merged = $this->mergeYaml($base, $ours, $theirs);

        if ($merged['clean']) {
            return CellMergeResult::resolved($merged['value']);
        }

        return CellMergeResult::conflict($ours);
    }
}

$config = (new CellMergeConfig())
    ->forColumn('config_data', new YamlCellMerger());