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.
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:
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:
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:
- Úplný názov stĺpca (
table.column). - Názov stĺpca bez kvalifikátora (
column). - Zhoda so vzorom typu stĺpca (bez rozlišovania veľkých a malých písmen
str_contains). - 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.
use Merql\CellMerge\TextCellMerger;
$merger = new TextCellMerger();
Príklad: čisté zlúčenie textu
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
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.
use Merql\CellMerge\JsonCellMerger;
$merger = new JsonCellMerger();
Príklad: čisté zlúčenie 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:
{"name": "Bob", "role": "admin", "active": true}
Príklad: konflikt 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.
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:
$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:
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:
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());