
# Einführung

merql ist eine reine PHP-Bibliothek für Drei-Wege-Merges von Datenbankzuständen. Sie erstellt Snapshots von Tabellen, berechnet Änderungen zwischen ihnen, führt zwei Änderungssätze anhand einer gemeinsamen Basis zusammen und erkennt Konflikte auf Spaltenebene. Derselbe Algorithmus wie bei git für Quelldateien, angewendet auf Zeilen und Spalten statt auf Zeilen im Text.

Keine externen Werkzeuge. Unterstützt MySQL und SQLite über austauschbare Verbindungsadapter und Dialekttreiber.

## Schnellstart-Beispiel

Für ein Merge brauchst du drei Zustände derselben Daten: die gemeinsame Basis beider Kopien und die beiden Kopien nach unabhängigen Änderungen. Hier wurde eine Sandbox aus der Live-Datenbank kopiert und beide wurden seitdem bearbeitet.

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

Erstelle jeden Snapshot aus der Datenbank, in der der jeweilige Zustand vorliegt. Alle drei Snapshots nacheinander aus einer Datenbank zu erstellen, bildet keine zwei auseinanderentwickelten Kopien ab: Theirs würde bereits die Änderungen von Ours enthalten, und jede von Ours eingefügte Zeile würde als `insert_insert`-Konflikt gemeldet.

Das Ergebnis listet die Vorgänge auf, die Base in den zusammengeführten Zustand überführen. Sie stammen von beiden Seiten und sind jeweils mit ihrer Quelle markiert (`ours`, `theirs` oder `merged`). Um die Änderungen der Sandbox in Live zu übernehmen, wende mit [Guarded Apply](https://merql.inline0.dev/de/docs/apply/guarded) nur die Vorgänge an, die Live noch fehlen.

Oder über CLI, das für jedes `snapshot` eine Verbindung zur in `MERQL_DB_DSN` angegebenen Datenbank herstellt:

```bash
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
```

## Warum merql

Die meisten Datenbankwerkzeuge zum Vergleichen von Zuständen arbeiten auf Zeilenebene: Unterscheidet sich in zwei Versionen auch nur eine Spalte einer Zeile, wird die gesamte Zeile als Konflikt markiert. Das führt zu falschen Konflikten, wenn zwei Personen verschiedene Spalten derselben Zeile bearbeiten.

merql führt Änderungen auf Spaltenebene zusammen. Ändert eine Seite `title` und die andere `status`, lassen sich diese Änderungen ohne Konflikt zusammenführen. Ein Konflikt entsteht nur, wenn beide Seiten dieselbe Spalte auf unterschiedliche Werte ändern.

Für TEXT- und JSON-Spalten kann merql mit einem Merge auf Zellenebene noch tiefer gehen. Zwei Änderungen an verschiedenen Zeilen einer Textspalte oder an verschiedenen Schlüsseln einer JSON-Spalte lassen sich mit demselben Drei-Wege-Algorithmus konfliktfrei zusammenführen. Das Merge auf Zellenebene ist optional: Übergib ein `CellMergeConfig` an `ThreeWayMerge`. Die Fassade `Merql` und CLI führen nur auf Spaltenebene zusammen. Siehe [Cell-Level Merge](https://merql.inline0.dev/de/docs/merge/cell-level).

## Das Merge-Modell

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

Drei Zustände wie bei git: Base ist der gemeinsame Vorfahr. Ours und Theirs sind die beiden Kopien nach ihrer Aufspaltung, jeweils aus der zugehörigen Datenbank erfasst. Die Merge-Regeln behandeln beide Seiten gleich. Die Namen erscheinen im `source` jedes Vorgangs, in Konflikttypen (`update_delete` bedeutet, dass Ours aktualisiert und Theirs gelöscht hat) sowie in den Auflösungsrichtlinien `OursWins` und `TheirsWins`. Ohne gemeinsame Basis lässt sich „hinzugefügt“ nicht von „unverändert“ unterscheiden.

Ein Merge schreibt selbst nichts in die Datenbank. Seine Vorgänge überführen Base in den zusammengeführten Zustand. `Merql::apply()` führt sie daher nur dann erfolgreich aus, wenn die Datenbank noch Base enthält. Um die Änderungen einer Seite in eine Datenbank zu übernehmen, die bereits die andere enthält, etwa Sandbox-Änderungen in Live, wende nur die noch fehlenden Vorgänge an. Siehe [Guarded Apply](https://merql.inline0.dev/de/docs/apply/guarded).

## Voraussetzungen

- PHP 8.2 oder neuer.
- `ext-mbstring` und `ext-zlib`, erforderlich für die Abhängigkeit `pitmaster/pitmaster`, die den Text-Diff bereitstellt.
- Eine Datenbankerweiterung für den verwendeten Adapter: `ext-pdo` mit `ext-pdo_sqlite` oder `ext-pdo_mysql` oder `ext-mysqli`. `composer.json` von merql schlägt nur `ext-pdo` und `ext-mysqli` vor; Composer prüft daher nicht, ob sie installiert sind.
- Eine MySQL- oder SQLite-Datenbank. Für andere Engines brauchst du einen benutzerdefinierten [driver](https://merql.inline0.dev/de/docs/apply/drivers).

## Was es nicht ist

merql ist kein Werkzeug für Schema-Migrationen. Es repliziert keine Datenbanken und synchronisiert sie nicht in Echtzeit. Es löst ein konkretes Problem: Ausgehend von drei Datenbankzuständen einen vierten, zusammengeführten Zustand mit erkannten Konflikten erzeugen.

## Dokumentation

- [Erste Schritte](https://merql.inline0.dev/de/docs/getting-started) – Installation, erster Snapshot, erstes Merge.
- [CLI Reference](https://merql.inline0.dev/de/docs/cli) – vollständige Referenz zum Befehl `vendor/bin/merql`.
- [PHP API Reference](https://merql.inline0.dev/de/docs/api) – vollständige API-Dokumentation aller Klassen.
- [Merge-Pläne](https://merql.inline0.dev/de/docs/merge/plans) – stabile Vorgangs-IDs, Änderungsgruppen und Auswahlmöglichkeiten.
- [Guarded Apply](https://merql.inline0.dev/de/docs/apply/guarded) – ausgewählte Schreibvorgänge mit Vorbedingungen für Live-Zeilen.
- [Rollback](https://merql.inline0.dev/de/docs/apply/rollback) – Rollback-Artefakte und Prüfungen auf Abweichungen.
