Imagine a scenario: two team members are working on different features, each requiring changes to the same record in a shared database. One updates a product’s price for a sale, while the other adjusts it due to supplier costs. When their work converges, how do you prevent one change from obliterating the other? This is the core problem of data merge conflicts, and knowing how to resolve them is an essential skill in any version-controlled data environment.

This chapter will guide you through the practical aspects of resolving data merge conflicts in Dolt. You’ll learn how Dolt, a Git-for-Data database, detects these clashes, how to inspect them using familiar dolt commands, and most importantly, how to systematically choose or combine changes to ensure data integrity. This understanding is critical for collaborative data management, maintaining audit trails, and managing complex data evolution in any Dolt-powered project. We’ll assume you’re comfortable with basic Dolt operations like committing, branching, and merging, as covered in previous chapters.

Understanding Dolt’s Data Merge Conflicts

Dolt brings the powerful version control paradigm of Git to SQL databases. Just as Git helps developers manage conflicting changes in code files, Dolt provides robust mechanisms to handle conflicts when merging divergent data histories.

What is a Data Merge Conflict?

A data merge conflict occurs when Dolt cannot automatically reconcile changes made to the same row or table in two different branches that are being merged. This situation typically arises under specific conditions:

  1. Same Cell, Different Values: Two branches modify the same cell (intersection of a row and column) with different values. For instance, two users update the price of product_id = 'P001' to different amounts.
  2. Row Deletion vs. Modification: One branch deletes a specific row, while another branch modifies that same row.
  3. Primary Key Collision: Both branches add a new row using the same primary key.
  4. Clashing Schema Changes: ALTER TABLE statements or other schema modifications on different branches fundamentally conflict (e.g., one renames a column, another drops it).

When Dolt detects such a clash, it pauses the merge, flags the conflicting data, and requires human intervention to decide which version of the data (or a combination thereof) should prevail.

How Dolt Detects Conflicts

Dolt detects conflicts at the row level and, for VALUE conflicts, at the cell level. It performs a three-way comparison, examining the state of the data in the common ancestor, the current branch (referred to as “ours”), and the branch being merged (referred to as “theirs”).

📌 Key Idea: Dolt doesn’t try to guess; it explicitly highlights where and what the conflict is, enabling precise and informed resolution.

Dolt categorizes conflicts into different types:

  • KEY Conflict: Occurs when a row’s primary key is modified differently on two branches, or when a new row is added with the same primary key on both branches.
  • VALUE Conflict: The most frequent type. This happens when different values are committed to the same cell (same column and row) by two different branches.
  • SCHEMA Conflict: Arises when schema modifications (like ALTER TABLE or DROP COLUMN) on different branches clash. These are typically resolved by manually applying the desired schema changes.

The Conflict Resolution Workflow

The process for resolving conflicts in Dolt mirrors the familiar Git workflow:

flowchart TD A[Start Merge] --> B{Conflicts Detected} B -->|No| C[Merge Successful] B -->|Yes| D[Inspect Conflicts] D --> E[Resolve Conflicts] E --> F[Commit Resolved Changes] F --> G[Merge Complete]

Step-by-Step Implementation: Simulating and Resolving a Data Conflict

Let’s get hands-on and intentionally create a conflict to observe Dolt’s behavior. We’ll use a simple products table, similar to what you might find in an inventory management system.

1. Initial Setup and Data

First, ensure you have Dolt installed (using version 1.34.4 as of 2026-06-06) and are in your preferred working directory.

# Verify Dolt installation
dolt version

# Initialize a new Dolt repository
dolt init

Now, let’s create our products table and populate it with some initial data. We’ll do this within the Dolt SQL shell.

dolt sql

Once inside the SQL shell, execute these commands:

CREATE TABLE products (
    product_id VARCHAR(50) PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    stock_quantity INT NOT NULL
);

INSERT INTO products (product_id, name, price, stock_quantity) VALUES
('P001', 'Laptop Pro', 1200.00, 50),
('P002', 'Wireless Mouse', 25.50, 200);

SELECT * FROM products;

You should see your newly inserted data. Now, exit the SQL shell and commit these changes.

QUIT; -- Exit the SQL shell
dolt add .
dolt commit -m "Initial products table and data"

This establishes a baseline for our divergent histories on the main branch.

2. Diverging Branches: Creating the Conflict

We’ll simulate two independent changes that target the same data point.

Step 2.1: Create a new branch for a price update. Let’s call this branch price-update.

dolt branch price-update
dolt checkout price-update

Step 2.2: On the price-update branch, modify the price. Imagine a marketing team member discounts the Laptop Pro.

dolt sql -q "UPDATE products SET price = 1150.00 WHERE product_id = 'P001';"
dolt add .
dolt commit -m "Feature: Discounted Laptop Pro on price-update branch"

Step 2.3: Switch back to main and make a conflicting change. Now, imagine a procurement team member (or an automated system) updates the same product’s price on main due to increased component costs.

dolt checkout main
dolt sql -q "UPDATE products SET price = 1250.00 WHERE product_id = 'P001';"
dolt add .
dolt commit -m "Main: Increased Laptop Pro price due to component cost"

At this point, we have two branches with divergent histories: main has P001 at 1250.00, and price-update has P001 at 1150.00. The stage is set for a conflict!

3. Attempting the Merge and Encountering Conflict

Let’s try to merge price-update into main.

dolt merge price-update

You should see output similar to this, clearly indicating a problem:

error: Merge conflict in table products:
    KEY: P001
    VALUE: price
Automatic merge failed; fix conflicts and then commit the result.

Success! Dolt explicitly tells us there’s a conflict in the products table, specifically for KEY: P001 and the VALUE in the price column. This is a classic VALUE conflict.

4. Inspecting Conflicts with dolt status and dolt diff

Once a conflict occurs, Dolt enters a “merging” state. Before resolving, we need to understand exactly what went wrong.

dolt status: Seeing the Conflict State

First, let’s check the status of our repository. This command provides an overview of the current state.

dolt status

You’ll see output similar to this:

On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
(use "dolt pull" to update your local branch)

You are currently merging branch 'price-update'.
  (fix conflicts and run "dolt commit")
  (use "dolt merge --abort" to abort the merge)

Unmerged paths:
  (use "dolt add <file>..." to mark resolution)
  (use "dolt checkout --ours <file>..." to discard local changes in favor of the branch being merged)
  (use "dolt checkout --theirs <file>..." to discard incoming changes in favor of the current branch)

        conflicted: products

This output clearly indicates that we are in a merge state, and the products table has conflicts that need our attention.

dolt diff: Understanding Conflicting Changes

The most powerful tool for granular inspection of conflicts is dolt diff. When in a merge state, dolt diff on a conflicting table shows the specific conflicting rows using standard Git conflict markers.

dolt diff products

The output for dolt diff products will focus on the conflicting row, showing its state in the common ancestor (if applicable, indicated by removed lines) and then the divergent states:

--- a/products
+++ b/products
@@ -1,1 +1,1 @@
-P001       | Laptop Pro   | 1200.00 | 50
+<<<<<<< HEAD
+P001       | Laptop Pro   | 1250.00 | 50
+=======
+P001       | Laptop Pro   | 1150.00 | 50
+>>>>>>> price-update

This output uses standard Git conflict markers:

  • -P001 | Laptop Pro | 1200.00 | 50: This line, prefixed with -, represents the state of the P001 row in the common ancestor commit.
  • <<<<<<< HEAD: Marks the beginning of the changes from the current branch (main).
  • P001 | Laptop Pro | 1250.00 | 50: This is how P001 appears on main.
  • =======: A separator between the two conflicting versions.
  • P001 | Laptop Pro | 1150.00 | 50: This is how P001 appears on the other branch (price-update).
  • >>>>>>> price-update: Marks the end of the changes from the price-update branch.

From this, it’s crystal clear that main (HEAD) has price = 1250.00 and price-update has price = 1150.00 for P001.

5. Resolving Conflicts

Now that we understand the conflict, it’s time to resolve it. Dolt provides specific commands to manage this process.

The dolt conflicts Command

Before diving into resolution, dolt conflicts provides a concise list of all pending conflicts in the current merge.

dolt conflicts

Output:

+------------+-------------+---------+
| Table      | Row         | Conflict|
+------------+-------------+---------+
| products   | P001        | VALUE   |
+------------+-------------+---------+

This confirms our VALUE conflict for P001 in the products table.

Resolution Strategies: ours, theirs, or Manual

Dolt offers several ways to resolve conflicts, ranging from quick, broad strokes to precise, manual adjustments:

  1. --ours: Choose the version from the current branch (main in our example). This strategy discards all conflicting changes from the branch being merged.
  2. --theirs: Choose the version from the other branch (price-update in our example). This strategy discards all conflicting changes from the current branch.
  3. Manual Resolution: Directly edit the data in the conflicting table to create a new, desired state. This offers the most control and is often preferred for complex or critical conflicts.

Let’s explore manual resolution first, as it demonstrates the highest level of control and understanding.

Step-by-Step Manual Resolution

For VALUE conflicts, Dolt creates a special set of tables that expose the conflicting data from all three perspectives (base, ours, theirs). These tables are named dolt_conflicts_<table_name>.

dolt sql

Inside the SQL shell, you can query these conflict tables to see the divergent values:

SELECT * FROM dolt_conflicts_products;

For our P001 conflict, you would see columns like product_id, base_price, our_price, and their_price (and similarly for other columns that might have conflicted).

Example output (simplified):

+------------+------------+-----------+------------+----------------+
| product_id | base_price | our_price | their_price| ...            |
+------------+------------+-----------+------------+----------------+
| P001       | 1200.00    | 1250.00   | 1150.00    | ...            |
+------------+------------+-----------+------------+----------------+

To manually resolve, you would directly UPDATE the products table to the desired state. Let’s say we decide to compromise and set the price to 1225.00.

UPDATE products SET price = 1225.00 WHERE product_id = 'P001';

After updating the table, you must inform Dolt that the conflict for that specific row has been resolved. This is done using the DOLT_RESOLVE stored procedure.

CALL DOLT_RESOLVE('products', 'P001');

This CALL DOLT_RESOLVE() statement is crucial. It tells Dolt that the conflict for the row identified by product_id = 'P001' in the products table has been handled.

Now, exit the SQL shell and check dolt conflicts again:

QUIT; -- Exit SQL shell
dolt conflicts

The output should now be empty, indicating no pending conflicts.

Finally, commit the resolved merge. This creates a new merge commit that incorporates the resolved changes.

dolt commit -m "Merged price-update, resolved conflict for P001 with price 1225.00"

The merge is now complete, and your main branch reflects the new, resolved state of the products table.

Using --ours or --theirs for Resolution

Sometimes, you simply want to accept all changes from one side without granular review. This is faster but less precise.

Let’s quickly recreate the conflict to demonstrate these options. (You can dolt reset --hard HEAD^ to undo the merge commit and then dolt merge price-update again to re-enter the conflict state).

# Assuming you are on 'main', and 'price-update' exists with conflicting changes.
# If you just completed the previous steps, you'd need to revert the merge commit:
dolt reset --hard HEAD~1
# Now, re-attempt the merge to get back into a conflict state:
dolt merge price-update

# Now in conflict state:
dolt status

If you decide to keep all changes from the current branch (main, which is “ours”):

dolt checkout --ours products

This command applies main’s version of the products table to the working set, effectively resolving all conflicts within that table by favoring main.

Alternatively, to favor all changes from price-update (the “theirs” branch):

dolt checkout --theirs products

After using either dolt checkout --ours or dolt checkout --theirs, the conflicts for that table are marked as resolved. You can verify with dolt conflicts and then proceed to commit the merge.

dolt conflicts # Should be empty
dolt commit -m "Merged price-update, resolved conflict by choosing --ours (main)"

Quick Note: dolt checkout --ours <table_name> and dolt checkout --theirs <table_name> resolve all conflicts within that table using the chosen strategy. If you need row-level or cell-level granularity for specific conflicts, manual resolution using UPDATE and CALL DOLT_RESOLVE is necessary.

Resolving Schema Conflicts

Schema conflicts occur when ALTER TABLE, DROP COLUMN, or other DDL (Data Definition Language) statements on different branches clash. For example, one branch renames a column while another drops it, or both modify the same column in incompatible ways.

Dolt will flag SCHEMA conflicts during a merge. Unlike VALUE conflicts, there isn’t a dolt_conflicts_<table_name> table for schema. You typically resolve these by:

  1. Inspecting the schema changes using dolt diff --schema. This command will show you the divergent schema definitions.
  2. Manually deciding which schema changes to keep, combine, or modify.
  3. Applying the desired final schema changes using dolt sql commands (e.g., ALTER TABLE).
  4. Staging the changes with dolt add . and then dolt commit.

This process usually involves carefully crafting a new ALTER TABLE statement that incorporates the desired elements from both conflicting schemas, potentially creating a new, unified schema.

Mini-Challenge: Create and Resolve Another Conflict

Let’s practice your conflict resolution skills with another scenario!

Challenge:

  1. Ensure you are currently on the main branch.
  2. Create a new branch named stock-update.
  3. On the stock-update branch, update the stock_quantity of P002 to 150. Commit this change.
  4. Switch back to the main branch.
  5. On main, update the stock_quantity of P002 to 250. Commit this change.
  6. Attempt to merge stock-update into main.
  7. Inspect the conflict using dolt status and dolt diff products.
  8. This time, resolve the conflict by choosing --theirs (meaning you want to keep the stock quantity from the stock-update branch).
  9. Commit the resolved merge.
  10. Verify the final stock_quantity for P002 on main using dolt sql -q "SELECT * FROM products WHERE product_id = 'P002';".

Hint: Remember the dolt checkout --theirs <table_name> command for quickly resolving all conflicts within a specified table by favoring the incoming branch.

What to observe/learn: You should see how dolt checkout --theirs quickly resolves all conflicts for a given table by favoring the incoming branch’s changes. The final stock_quantity for P002 on your main branch should be 150.

Common Pitfalls & Troubleshooting

Ignoring Conflicts

⚠️ What can go wrong: Forgetting that dolt merge reported an error and continuing to work on the database without resolving conflicts. This leaves your repository in a “merging” state, preventing further commits until the conflicts are addressed. Your database state is ambiguous.

Troubleshooting: Always check dolt status immediately after a dolt merge operation. If it says You are currently merging branch '...', you have conflicts to resolve. If you decide to abandon the merge altogether, use dolt merge --abort.

Overwriting Data Without Understanding

⚠️ What can go wrong: Blindly using --ours or --theirs without first using dolt diff to fully understand the impact of the conflicting changes. This can lead to unintended data loss or the commitment of incorrect data.

Troubleshooting: Always use dolt diff <table_name> to thoroughly inspect the conflicting data before choosing a resolution strategy, especially in production environments or for critical datasets. For sensitive data, manual resolution with UPDATE and CALL DOLT_RESOLVE provides the highest level of control and auditability.

Complex Multi-Row Conflicts

⚠️ What can go wrong: While Dolt handles row-level and cell-level conflicts very well, a large number of conflicts across many rows or tables can still be daunting and time-consuming to resolve manually.

Troubleshooting:

  • Commit frequently: Smaller, more focused commits reduce the likelihood and complexity of conflicts by narrowing the scope of changes.
  • Implement a clear branching strategy: A well-defined strategy can help minimize parallel work on the exact same data, reducing the chances of conflicts.
  • Automated resolution: For predictable types of conflicts (e.g., always prefer the latest timestamp for a last_updated column), consider scripting custom resolution logic using Dolt’s client libraries or hooks.

Summary

You’ve now gained a crucial skill: mastering the resolution of data merge conflicts in Dolt. This capability is what truly elevates Dolt beyond a traditional RDBMS, making it a robust Git-for-Data solution that enables collaborative data development without fear of overwriting critical information.

Here’s a quick recap of the key takeaways from this chapter:

  • Data merge conflicts occur when Dolt cannot automatically reconcile divergent changes to the same data across branches.
  • Dolt detects KEY, VALUE, and SCHEMA conflicts at a granular level.
  • dolt status is your first stop to identify the merge state and which tables have conflicts.
  • dolt diff <table_name> is the essential tool for inspecting the exact conflicting changes using Git-style markers, showing base, ours, and theirs versions of conflicting rows.
  • You can resolve conflicts using dolt checkout --ours <table_name> (favor current branch), dolt checkout --theirs <table_name> (favor incoming branch), or through precise manual resolution with UPDATE statements and the CALL DOLT_RESOLVE('<table_name>', '<primary_key>') procedure.
  • Always dolt commit your resolved changes to finalize the merge.
  • Schema conflicts require careful manual review of dolt diff --schema output and ALTER TABLE statements to unify the schema.

In the next chapter, we’ll build upon this solid understanding of branching, merging, and conflict resolution to explore advanced collaboration workflows using Dolt remotes and DoltHub, taking your data version control capabilities to an enterprise scale.

References

  1. Dolt Documentation - Merge Conflicts: https://www.dolthub.com/docs/latest/reference/cli/dolt-merge#merge-conflicts
  2. Dolt Documentation - dolt conflicts: https://www.dolthub.com/docs/latest/reference/cli/dolt-conflicts
  3. Dolt Documentation - dolt resolve: https://www.dolthub.com/docs/latest/reference/sql/dolt-resolve
  4. Dolt Documentation - dolt diff: https://www.dolthub.com/docs/latest/reference/cli/dolt-diff
  5. DoltHub Blog - How Dolt Diff Works: https://www.dolthub.com/blog/2021-03-04-how-dolt-diff-works/

This page is AI-assisted and reviewed. It references official documentation and recognized resources where relevant.