Previewing Merge Conflicts

FEATURE RELEASEWEB
9 min read

Dolt is Git for data. One of the most powerful features of Git is the ability to view and resolve merge conflicts when two developers make code changes on different branches to the same line. In Dolt, conflicts can also be triggered but follow more complicated rules. Data conflicts arise when two editors modify the same cell (ie. row, column pair). Schema conflicts can also occur but follow different rules.

Previously in Dolt, merge conflicts could only be viewed and resolved after a merge was attempted. Now we are excited to announce that you are able to preview merge conflicts before attempting a merge from both Dolt's SQL interface and from pull requests on the web.

In this post, I'll walk you through how to use this new feature, both through the web interface and SQL.

Why We Couldn't Preview Merge Conflicts Before

The technical challenge behind merge conflict previewing comes down to how merge logic was originally structured in Dolt. Previously, the conflict detection logic wasn't separated from the actual merge operation itself. When you ran a merge, Dolt would simultaneously:

  1. Attempt to combine changes from both branches
  2. Detect where conflicts occurred
  3. Write conflict markers to the database

This meant there was no way to "peek ahead" and see what conflicts would arise without actually performing the merge. The conflict detection was tightly coupled with the merge execution.

We had previously refactored the merge logic to expose an interface for three-way diff without performing a merge. This was needed for gathering statistics and pull request information, but it also made it easier to implement merge conflict preview so you can view conflicts before modifying your database.

When Merge Conflicts Happen

Merge conflicts in Dolt occur when two users edit the same cell on different branches. This is similar to how conflicts work in Git, but instead of conflicting text lines, you're dealing with conflicting database values at the individual cell level.

For example, you and a teammate both check out the main branch around the same time. You both make edits to the same customer record, maybe you both make changes to a customer's email. When the first person merges their branch, everything goes smoothly. But when the second person tries to merge, Dolt detects that the same cells were modified in different ways and flags them as conflicts.

Why Preview Merge Conflicts?

Previewing merge conflicts before attempting a merge has several benefits:

  1. Merge with confidence: You can verify that a merge will be successful before executing it, preventing your database from ending up in a conflicted state.

  2. Better conflict visualization: Previewing merge conflicts on the web provides a clearer way to visualize exactly which cells are conflicting in which rows compared to the SQL or CLI interfaces.

  3. Plan your resolution strategy: You can examine all conflicts upfront and decide how to resolve them before committing to the merge.

Previewing Merge Conflicts on the Web

The merge conflict preview feature is currently available in Hosted Dolt and the Dolt Workbench. Support for DoltHub and DoltLab is coming soon.

Here's how to use it:

Step 1: Create a Conflicted Scenario

Using the Dolt Workbench desktop application, we cloned the dolthub/employees database from DoltHub to have a local copy we can modify.

Clone from Dolt Workbench

Human Resources was tasked with normalizing the employee salaries so they are rounded to the nearest thousand.

Employee salaries

Two HR colleagues check out branches from main to make this change. One colleague checks out branch round-up and updates the salaries so they are rounded up to the nearest thousand.

Round up salaries

The other colleague checks out branch round-down and updates the salaries so they are rounded down to the nearest thousand.

Round down salaries

The round-down colleague reviews their pull request first and decides to merge.

Round down pull request

Step 2: View Conflicts in the Pull Request

The round-up colleague looks at the pull request for their branch and sees that there are almost 3 million data conflicts in the salaries table.

Round up pull request conflicts

They cannot merge their branch until the conflicts are resolved.

Step 3: Examine Individual Row Conflicts

The round-up colleague can click on the salaries table link in the pull request to view the individual cell-level conflicts.

Salaries conflicted rows

This interface shows you:

  • The original value from the merge base commit (the value of the cell when round-up was checked out from main)
  • The changes from the base branch (main)
  • The changes from the merge branch (round-up)
  • Clear highlighting of which specific cells conflict

From this clear interface, even an HR representative can clearly see what happened here. One colleague rounded up, making employees happy. The other rounded down, making employees sad.

Step 4: Resolve Conflicts

Currently, you need to resolve conflicts using either the SQL interface or CLI (web-based conflict resolution is coming soon). Since we started a local SQL server using the workbench, we can connect using the port we specified in the first step. The company decides they want the salaries rounded up after all, so we need to resolve the conflicts to the value of the round-up branch, or theirs.

First, connect to the local SQL server and turn off AUTOCOMMIT. Because SQL transactions and Dolt merges share the same transaction merge code, interactive Dolt merges must be performed in a single transaction in the SQL context. This means you must turn off AUTOCOMMIT.

taylor@MacBook-Pro-6 ~ % mysql -h 127.0.0.1 -P 3658 -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 8.0.33 Dolt

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use employees;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

mysql> set @@autocommit = 0;
Query OK, 1 row affected (0.004 sec)

We should be on the main branch, and if we attempt to merge round-up, we can view the conflicts.

mysql> call dolt_merge('round-up');
+------+--------------+-----------+-----------------+
| hash | fast_forward | conflicts | message         |
+------+--------------+-----------+-----------------+
|      |            0 |         1 | conflicts found |
+------+--------------+-----------+-----------------+
1 row in set, 1 warning (10.850 sec)

mysql> select * from dolt_conflicts;
+----------+---------------+
| table    | num_conflicts |
+----------+---------------+
| salaries |       2745992 |
+----------+---------------+
1 row in set (0.651 sec)

mysql> select * from dolt_conflicts_salaries limit 5;
+----------------------------------+-------------+----------------+-------------+--------------+------------+---------------+------------+-------------+---------------+--------------+-----------------+--------------+---------------+-----------------+------------------------+
| from_root_ish                    | base_emp_no | base_from_date | base_salary | base_to_date | our_emp_no | our_from_date | our_salary | our_to_date | our_diff_type | their_emp_no | their_from_date | their_salary | their_to_date | their_diff_type | dolt_conflict_id       |
+----------------------------------+-------------+----------------+-------------+--------------+------------+---------------+------------+-------------+---------------+--------------+-----------------+--------------+---------------+-----------------+------------------------+
| 6rp2t7r102l7u3s555umovr5m88pljil |       10001 | 1986-06-26     |       60117 | 1987-06-26   |      10001 | 1986-06-26    |      60000 | 1987-06-26  | modified      |        10001 | 1986-06-26      |        61000 | 1987-06-26    | modified        | SWiQoSu6klSV5yhri1+0Gw |
| 6rp2t7r102l7u3s555umovr5m88pljil |       10001 | 1987-06-26     |       62102 | 1988-06-25   |      10001 | 1987-06-26    |      62000 | 1988-06-25  | modified      |        10001 | 1987-06-26      |        63000 | 1988-06-25    | modified        | FZ/rlxG4rpaPlx+2Q+iQvg |
| 6rp2t7r102l7u3s555umovr5m88pljil |       10001 | 1988-06-25     |       66074 | 1989-06-25   |      10001 | 1988-06-25    |      66000 | 1989-06-25  | modified      |        10001 | 1988-06-25      |        67000 | 1989-06-25    | modified        | zOETYlkaLyG+qOWYiNISOg |
| 6rp2t7r102l7u3s555umovr5m88pljil |       10001 | 1989-06-25     |       66596 | 1990-06-25   |      10001 | 1989-06-25    |      66000 | 1990-06-25  | modified      |        10001 | 1989-06-25      |        67000 | 1990-06-25    | modified        | ky6DG/KC7pO1TcfDkr2cmg |
| 6rp2t7r102l7u3s555umovr5m88pljil |       10001 | 1990-06-25     |       66961 | 1991-06-25   |      10001 | 1990-06-25    |      66000 | 1991-06-25  | modified      |        10001 | 1990-06-25      |        67000 | 1991-06-25    | modified        | BTUXiF8T8WoenpnDiP86kw |
+----------------------------------+-------------+----------------+-------------+--------------+------------+---------------+------------+-------------+---------------+--------------+-----------------+--------------+---------------+-----------------+------------------------+
5 rows in set (0.004 sec)

You can see how much the web UI improves viewing the cell-level conflicts!

Finally, we can use the dolt_conflicts_resolve SQL procedure to choose the values from the theirs changes (i.e., the round-up branch) and commit the merge.

mysql> call dolt_conflicts_resolve('--theirs', 'salaries');
+--------+
| status |
+--------+
|      0 |
+--------+
1 row in set (20.896 sec)

mysql> call dolt_commit('-Am', 'Resolved salary conflicts');
+----------------------------------+
| hash                             |
+----------------------------------+
| 54v68puuvjttgastsh04n589om9tm2aj |
+----------------------------------+
1 row in set (0.014 sec)

If we go back to the desktop app, we can see that the salaries table has the new values.

Rounded up salaries

Using SQL Table Functions

For those who prefer working directly with SQL, Dolt provides two new table functions for previewing merge conflicts:

dolt_preview_merge_conflicts_summary

This function gives you a high-level overview of which tables have conflicts:

SELECT * FROM dolt_preview_merge_conflicts_summary(<base_branch>, <merge_branch>);

This returns a summary showing:

  • Table names with conflicts
  • Number of schema conflicts
  • Number of data conflicts (empty if there are schema conflicts)

The results of this table are similar to the dolt_conflicts system table, which can be viewed after attempting a merge with conflicts.

Here's what the results would look like for the round-up branch before we resolved them above:

mysql> SELECT * FROM dolt_preview_merge_conflicts_summary('main', 'round-up');
+----------+--------------------+----------------------+
| table    | num_data_conflicts | num_schema_conflicts |
+----------+--------------------+----------------------+
| salaries |            2745992 |                    0 |
+----------+--------------------+----------------------+
1 row in set (3.344 sec)

dolt_preview_merge_conflicts

For detailed cell-level conflict information, use this function:

SELECT * FROM dolt_preview_merge_conflicts(<base_branch>, <merge_branch>, <table_name>);

This shows the actual conflicted data, with columns for:

  • Base values (from the common ancestor)
  • Ours values (from your current branch)
  • Theirs values (from the target branch)
  • Diff type of the ours and theirs conflicted rows ("added", "modified", "removed")
  • Specific cell identifiers showing which cells have conflicts

The results of this table are similar to the dolt_conflicts_$tablename system table, which can be viewed after attempting a merge with conflicts.

Here's what the results would look like for the salaries table on the round-up branch before we resolved them above:

mysql> SELECT * FROM dolt_preview_merge_conflicts('main', 'round-up', 'salaries') LIMIT 5;
+----------------------------------+-------------+----------------+-------------+--------------+------------+---------------+------------+-------------+---------------+--------------+-----------------+--------------+---------------+-----------------+------------------------+
| from_root_ish                    | base_emp_no | base_from_date | base_salary | base_to_date | our_emp_no | our_from_date | our_salary | our_to_date | our_diff_type | their_emp_no | their_from_date | their_salary | their_to_date | their_diff_type | dolt_conflict_id       |
+----------------------------------+-------------+----------------+-------------+--------------+------------+---------------+------------+-------------+---------------+--------------+-----------------+--------------+---------------+-----------------+------------------------+
| 6rp2t7r102l7u3s555umovr5m88pljil |       10001 | 1986-06-26     |       60117 | 1987-06-26   |      10001 | 1986-06-26    |      60000 | 1987-06-26  | modified      |        10001 | 1986-06-26      |        61000 | 1987-06-26    | modified        | SWiQoSu6klSV5yhri1+0Gw |
| 6rp2t7r102l7u3s555umovr5m88pljil |       10001 | 1987-06-26     |       62102 | 1988-06-25   |      10001 | 1987-06-26    |      62000 | 1988-06-25  | modified      |        10001 | 1987-06-26      |        63000 | 1988-06-25    | modified        | FZ/rlxG4rpaPlx+2Q+iQvg |
| 6rp2t7r102l7u3s555umovr5m88pljil |       10001 | 1988-06-25     |       66074 | 1989-06-25   |      10001 | 1988-06-25    |      66000 | 1989-06-25  | modified      |        10001 | 1988-06-25      |        67000 | 1989-06-25    | modified        | zOETYlkaLyG+qOWYiNISOg |
| 6rp2t7r102l7u3s555umovr5m88pljil |       10001 | 1989-06-25     |       66596 | 1990-06-25   |      10001 | 1989-06-25    |      66000 | 1990-06-25  | modified      |        10001 | 1989-06-25      |        67000 | 1990-06-25    | modified        | ky6DG/KC7pO1TcfDkr2cmg |
| 6rp2t7r102l7u3s555umovr5m88pljil |       10001 | 1990-06-25     |       66961 | 1991-06-25   |      10001 | 1990-06-25    |      66000 | 1991-06-25  | modified      |        10001 | 1990-06-25      |        67000 | 1991-06-25    | modified        | BTUXiF8T8WoenpnDiP86kw |
+----------------------------------+-------------+----------------+-------------+--------------+------------+---------------+------------+-------------+---------------+--------------+-----------------+--------------+---------------+-----------------+------------------------+
5 rows in set (0.007 sec)

You can use these functions to build custom conflict resolution workflows or integrate merge conflict detection into your CI/CD pipelines.

Future Work

This is just the beginning of our merge conflict tooling improvements. Here's what we're working on next:

DoltHub and DoltLab support: These platforms don't directly use the SQL interface, so implementing preview functionality is more involved. This is coming within the next week or so.

CLI preview commands: We plan to add equivalent preview merge conflicts commands to the Dolt CLI.

Constraint violation detection: Currently, the preview focuses on data and schema conflicts. We want to extend this to also preview constraint violations that might occur during a merge.

Web-based conflict resolution: The ultimate goal is to let you resolve conflicts directly from the web interface without needing to touch SQL or the CLI at all.

Conclusion

Merge conflict previewing has been a requested feature for some time, and we're excited to continue building tools and features to make this process more seamless.

This feature is available now in Hosted Dolt and Dolt Workbench, with DoltHub and DoltLab support coming soon. Try it out on your next project and let us know what you think!

Have questions about merge conflict previewing or want to share your experience with the feature? Join us on Discord - we'd love to hear from you.

SHARE

JOIN THE DATA EVOLUTION

Get started with Dolt

Or join our mailing list to get product updates.