Sammanslagning på cellnivå
Sammanslagning på kolumnnivå upptäcker när båda sidorna har ändrat samma kolumn. Sammanslagning på cellnivå går djupare och slår samman innehållet i kolumnen. Två personer som redigerar olika rader i ett fält av typen TEXT, eller olika nycklar i ett objekt av typen JSON, kan slå samman ändringarna utan konflikt.
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;
$config = CellMergeConfig::auto();
$merge = new ThreeWayMerge($config);
$result = $merge->merge($base, $ours, $theirs);
Aktivera sammanslagning på cellnivå
Sammanslagning på cellnivå är valfri. Den körs endast i en ThreeWayMerge som konstruerats med en CellMergeConfig. Utan en sådan är varje kolumn som båda sidor ändrat till olika värden en update_update-konflikt.
Gränssnittet Merql tar ingen konfiguration: Merql::merge(), Merql::patch() och Merql::plan() konstruerar new ThreeWayMerge() utan någon, och kommandot merge i CLI går via Merql::merge(). De slår alltid samman på kolumnnivå (#7).
Om du vill slå samman ögonblicksbilder som sparats av gränssnittet eller CLI med sammanslagning på cellnivå läser du in dem och anropar själv ThreeWayMerge. Resultatet är en vanlig MergeResult, så gränssnittet kan fortfarande tillämpa det, och MergePlanBuilder omvandlar det till en sammanslagningsplan:
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);
Cell-sammanslagare körs endast för kolumner som båda sidorna har ändrat. Om bara den ena sidan har ändrat en kolumn används dess värde som det är.
CellMergeConfig
CellMergeConfig mappar kolumner eller kolumntyper till implementationer av cell-sammanslagare. Fabriken auto() tillhandahåller lämpliga standardinställningar:
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());
Prioritetsordning för sammanslagare:
- Kvalificerat kolumnnamn (
table.column). - Okvalificerat kolumnnamn (
column). - Matchning av kolumntypmönster (skiftlägesokänslig
str_contains). - Standard:
OpaqueCellMerger(rapporterar alltid en konflikt när värden skiljer sig).
TextCellMerger
Slår samman flerradig text med Myers diff, samma algoritm som git använder för filinnehåll. Varje rad behandlas som en enhet, och ändringar på olika rader slås samman utan konflikt.
use Merql\CellMerge\TextCellMerger;
$merger = new TextCellMerger();
Exempel: konfliktfri textsammanslagning
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
Olika rader redigerades. Sammanslagningen ger "LINE ONE\nline two\nLINE THREE" utan konflikt.
Exempel: textkonflikt
Base: "line one\nline two"
Ours: "changed by us\nline two" // changed line 1
Theirs: "changed by them\nline two" // also changed line 1
Båda sidorna ändrade samma rad till olika värden. Sammanslagaren returnerar ett konfliktresultat. Det sammanslagna innehållet innehåller konfliktmarkörer som liknar git.
Så fungerar det
TextCellMerger använder pitmasters ThreeWayMerge::merge(), som beräknar en Myers diff mellan basen och varje sida och sedan kombinerar de två redigeringssekvenserna. Om ändringarna överlappar i samma radområde rapporteras en konflikt.
JsonCellMerger
Slår samman objekt av typen JSON genom att jämföra toppnivånycklar var för sig. Varje nyckel slås samman enligt de vanliga trevägsreglerna.
use Merql\CellMerge\JsonCellMerger;
$merger = new JsonCellMerger();
Exempel: konfliktfri sammanslagning av 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}
Olika nycklar ändrades. Det sammanslagna resultatet är:
{"name": "Bob", "role": "admin", "active": true}
Exempel: konflikt i JSON
// Base
{"color": "red"}
// Ours
{"color": "blue"}
// Theirs
{"color": "green"}
Båda sidorna ändrade nyckeln color till olika värden. Det är en konflikt. Sammanslagaren använder som standard vårt värde och rapporterar en konflikt.
Regler på nyckelnivå
| Bas | Vår | Deras | Resultat |
|---|---|---|---|
| Nyckel oförändrad | Nyckel oförändrad | Acceptera basen | |
| Nyckel oförändrad | Nyckel ändrad | Acceptera deras | |
| Nyckel ändrad | Nyckel oförändrad | Acceptera vårt | |
| Nyckel ändrad (samma) | Nyckel ändrad (samma) | Acceptera (överens) | |
| Nyckel ändrad (olika) | Nyckel ändrad (olika) | Konflikt (standard: vårt) | |
| Nyckel finns | Nyckel finns | Nyckel borttagen | Acceptera borttagningen |
| Nyckel finns | Nyckel borttagen | Nyckel finns | Acceptera borttagningen |
| Nyckel saknas | Nyckel tillagd | Nyckel saknas | Acceptera tillägget |
| Nyckel saknas | Nyckel saknas | Nyckel tillagd | Acceptera tillägget |
Kapslade objekt jämförs som ogenomskinliga strängar av typen JSON, inte rekursivt. Om ett kapslat objekt skiljer sig åt jämförs hela värdet för nyckeln, inte dess undernycklar.
Krav
Alla tre värden måste vara giltiga objekt eller arrayer av typen JSON. Om något värde inte är giltig JSON, eller är en skalär av typen JSON (sträng, tal, booleskt värde), faller sammanslagaren tillbaka till en konflikt.
OpaqueCellMerger
Standardsammanslagaren när ingen strategi för cellnivå har konfigurerats. Den behandlar kolumnvärdet som en ogenomskinlig blob och rapporterar alltid en konflikt när de båda sidornas värden skiljer sig åt.
use Merql\CellMerge\OpaqueCellMerger;
$merger = new OpaqueCellMerger();
$result = $merger->merge($base, $ours, $theirs);
// $result->clean is always false when $ours !== $theirs
CellMergeResult
Alla cell-sammanslagare returnerar en 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
Fabriksmetoder:
CellMergeResult::resolved($value); // clean merge
CellMergeResult::conflict($oursValue, $n); // n conflicts, defaults to ours
Anpassade cell-sammanslagare
Implementera gränssnittet CellMerger för att lägga till en egen sammanslagningsstrategi:
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());