Conflicts#

What is a Conflict?#

A conflict is a signal to a user that a merge has produced a database that requires further action. The merge algorithm could not infer the state of the database based on the merge rules after the merge. Further input is required to tell Doltgres what the resulting merged database should contain.

In Doltgres, conflicts can occur on data and schema.

Data#

On data, conflicts are detected on a cell-level. If two operations modify the same row, column pair to be different values, a conflict is detected. Primary key values are used to identify rows across versions for the purpose of diff and merge.

A caveat here is columns of JSON type. If two cells of JSON type are modified on both sides of a merge, Doltgres will make an attempt to merge the underlying JSON objects. Currently, changes that modify different keys in a JSON object are merged without generating conflicts. Changes that modify the same keys will generate conflicts. Over time, we seek to improve conflict-free merging of JSON objects.

In the case of keyless tables, every column is considered part of the primary key for merge. Thus, conflicts can only be generated in keyless tables if one side of the merge deletes a row and the other side adds the same row.

Schema#

Two branches must add, delete or modify a similarly named table, column, foreign key, index or constraint to generate a schema conflict, otherwise the changes are mergeable.

If two branches modify the same named table, column, foreign key, index or check constraint, consult the following tables for conflict detection.

Tables#

Left BranchRight BranchCaveatMergeable
Add t1Add t1Same SchemaYes
Add t1Add t1Different SchemaSchema Conflict
Delete t1Delete t1Yes
Modify t1Delete t1Schema Conflict
Modify t1Modify t1Same SchemaYes
Modify t1Modify t1Different SchemaSchema Conflict

Columns#

Left BranchRight BranchCaveatMergeable
Delete c1Delete c1Yes
Modify c1Delete c1Schema Conflict
Add c1Add c1Same Type, Same Constraints, Same DataYes
Add c1Add c1Different TypeSchema Conflict
Add c1Add c1Same Type, Different ConstraintsSchema Conflict
Add c1Add c1Same Type, Same Constraints, Different DataData Conflict
Modify c1Modify c1Same Type, Same Constraints, Same DataYes
Modify c1Modify c1Incompatible Type ChangeSchema Conflict
Modify c1Modify c1Compatible Type ChangeYes
Modify c1Modify c1Same Type, Different ConstraintsSchema Conflict
Modify c1Modify c1Same Type, Same Constraints, Different DataData Conflict

Foreign Keys#

Left BranchRight BranchCaveatMergeable
Add fk1Add fk1Same definitionYes
Add fk1Add fk1Different definitionSchema Conflict
Delete t1Delete t1Yes
Modify fk1Delete fk1Schema Conflict
Modify fk1Modify fk1Same definitionYes
Modify fk1Modify fk1Different definitionSchema Conflict

Indexes#

Left BranchRight BranchCaveatMergeable
Add i1Add i1Same definitionYes
Add i1Add i1Different definitionSchema Conflict
Delete i1Delete i1Yes
Modify i1Delete i1Schema Conflict
Modify i1Modify i1Same definitionYes
Modify i1Modify i1Different definitionSchema Conflict

Check Constraints#

Left BranchRight BranchCaveatMergeable
Add ck1Add ck1Same definitionYes
Add ck1Add ck1Different definitionSchema Conflict
Delete ck1Delete ck1Yes
Modify ck1Delete ck1Schema Conflict
Modify ck1Modify ck1Same definitionYes
Modify ck1Modify ck1Different definitionSchema Conflict

How to use Conflicts#

Conflicts signal to the user that a merge is risky. In the event of a conflict, you can either redo the changes on the tip of the branch you are merging into or resolve the conflicts.

In the case of conflict resolution Doltgres supports two automated resolution strategies, ours or theirs. You can choose to keep the state of schema or data on the branch you are on or the branch you are merging.

If you would like to manually resolve conflicts, you can set the value of the row that has the conflict to whatever you would like and then resolve the conflict by deleting the corresponding conflict row in dolt_conflicts_<tablename>.

Difference between Git conflicts and Doltgres conflicts#

Conflicts are a major divergence from Git in Doltgres. Conceptually, Doltgres and Git conflicts are similar, but in practice the Doltgres conflict management workflow and user interface is very different.

In Doltgres, conflicts are stored in the dolt_conflicts set of tables. Each table in your database has an associated dolt_conflicts table. For instance if you have a table named docs, there is a system table named dolt_conflicts_docs. This replaces the >>> and <<< syntax that is inserted into your files in Git when conflicts occur.

Doltgres conflicts can occur on schema or data. In Git, conflicts can only occur on lines in files. So Doltgres has two types of conflicts whereas Git has one type.

In the case of foreign keys, Doltgres can produce invalid merges even after conflicts are resolved. In Doltgres, this merge will not be able to be committed until the foreign key violations are resolved. In Git, a repository with no conflict markers is a valid repository and can be committed.

Example#

Generating a Conflict#

select * from docs;
+----+----+
| pk | c1 |
+----+----+
| 0  | 0  |
| 1  | 1  |
| 2  | 2  |
+----+----+
select dolt_branch('make-conflicts');
update docs set c1=10 where pk=1;
select * from docs;
+----+----+
| pk | c1 |
+----+----+
| 0  | 0  |
| 1  | 10 |
| 2  | 2  |
+----+----+
select dolt_commit('-Am', 'Made pk=1, c1=10');
select dolt_checkout('make-conflicts');
select * from docs;
+----+----+
| pk | c1 |
+----+----+
| 0  | 0  |
| 1  | 1  |
| 2  | 2  |
+----+----+
update docs set c1=0 where pk=1;
select * from docs;
+----+----+
| pk | c1 |
+----+----+
| 0  | 0  |
| 1  | 0  |
| 2  | 2  |
+----+----+
select dolt_commit('-m', 'Made pk=1, c1=0');
select dolt_checkout('main');
select dolt_merge('make-conflicts'); -- conflict created

Resolving a Conflict#

select dolt_conflicts_resolve('--ours', 'docs');
select * from docs;
+----+----+
| pk | c1 |
+----+----+
| 0  | 0  |
| 1  | 10 |
| 2  | 2  |
+----+----+
select dolt_commit('-m', 'Resolved conflict');