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:
- 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
priceofproduct_id = 'P001'to different amounts. - Row Deletion vs. Modification: One branch deletes a specific row, while another branch modifies that same row.
- Primary Key Collision: Both branches add a new row using the same primary key.
- Clashing Schema Changes:
ALTER TABLEstatements 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:
KEYConflict: 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.VALUEConflict: The most frequent type. This happens when different values are committed to the same cell (same column and row) by two different branches.SCHEMAConflict: Arises when schema modifications (likeALTER TABLEorDROP 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:
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 initNow, let’s create our products table and populate it with some initial data. We’ll do this within the Dolt SQL shell.
dolt sqlOnce 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 shelldolt 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-updateStep 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-updateYou 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 statusYou’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: productsThis 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 productsThe 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-updateThis output uses standard Git conflict markers:
-P001 | Laptop Pro | 1200.00 | 50: This line, prefixed with-, represents the state of theP001row 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 howP001appears onmain.=======: A separator between the two conflicting versions.P001 | Laptop Pro | 1150.00 | 50: This is howP001appears on the other branch (price-update).>>>>>>> price-update: Marks the end of the changes from theprice-updatebranch.
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 conflictsOutput:
+------------+-------------+---------+
| 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:
--ours: Choose the version from the current branch (mainin our example). This strategy discards all conflicting changes from the branch being merged.--theirs: Choose the version from the other branch (price-updatein our example). This strategy discards all conflicting changes from the current branch.- 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 sqlInside 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 shelldolt conflictsThe 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 statusIf you decide to keep all changes from the current branch (main, which is “ours”):
dolt checkout --ours productsThis 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 productsAfter 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:
- Inspecting the schema changes using
dolt diff --schema. This command will show you the divergent schema definitions. - Manually deciding which schema changes to keep, combine, or modify.
- Applying the desired final schema changes using
dolt sqlcommands (e.g.,ALTER TABLE). - Staging the changes with
dolt add .and thendolt 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:
- Ensure you are currently on the
mainbranch. - Create a new branch named
stock-update. - On the
stock-updatebranch, update thestock_quantityofP002to150. Commit this change. - Switch back to the
mainbranch. - On
main, update thestock_quantityofP002to250. Commit this change. - Attempt to merge
stock-updateintomain. - Inspect the conflict using
dolt statusanddolt diff products. - This time, resolve the conflict by choosing
--theirs(meaning you want to keep the stock quantity from thestock-updatebranch). - Commit the resolved merge.
- Verify the final
stock_quantityforP002onmainusingdolt 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_updatedcolumn), 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, andSCHEMAconflicts at a granular level. dolt statusis 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 withUPDATEstatements and theCALL DOLT_RESOLVE('<table_name>', '<primary_key>')procedure. - Always
dolt commityour resolved changes to finalize the merge. - Schema conflicts require careful manual review of
dolt diff --schemaoutput andALTER TABLEstatements 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
- Dolt Documentation - Merge Conflicts: https://www.dolthub.com/docs/latest/reference/cli/dolt-merge#merge-conflicts
- Dolt Documentation - dolt conflicts: https://www.dolthub.com/docs/latest/reference/cli/dolt-conflicts
- Dolt Documentation - dolt resolve: https://www.dolthub.com/docs/latest/reference/sql/dolt-resolve
- Dolt Documentation - dolt diff: https://www.dolthub.com/docs/latest/reference/cli/dolt-diff
- 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.