Branch Management Guide
Overview
MatrixOne’s branch management feature allows you to create isolated branches of your database for development, testing, and experimentation without affecting the main database. Branches are lightweight and efficient, making them ideal for:
Development and testing
Feature branches for different teams
Safe experimentation with schema changes
Parallel development workflows
Version Requirement: MatrixOne 3.0.5 or higher
Creating and Managing Branches
Basic Branch Operations
from matrixone import Client
client = Client()
client.connect(database='test')
# Create a table branch
client.branch.create_table_branch(
target_table='users_branch',
source_table='users'
)
# Create a database branch
client.branch.create_database_branch(
target_database='dev_db',
source_database='main_db'
)
# Delete a table branch
client.branch.delete_table_branch('users_branch')
# Delete a database branch
client.branch.delete_database_branch('dev_db')
Simplified API
For convenience, you can use the simplified API that auto-detects table vs database operations:
from matrixone import Client
client = Client()
client.connect(database='test')
# Create table branch (simplified)
client.branch.create('users_branch', 'users')
# Create database branch (simplified)
client.branch.create('dev_db', 'main_db', database=True)
# Delete table branch (simplified)
client.branch.delete('users_branch')
# Delete database branch (simplified)
client.branch.delete('dev_db', database=True)
Branch Workflow Example
from matrixone import Client
client = Client()
client.connect(database='production')
# Create a development branch from production database
client.branch.create_database_branch(
target_database='feature_branch',
source_database='production'
)
# Make changes in the branch database
client.execute("USE feature_branch")
client.execute("""
ALTER TABLE users ADD COLUMN new_field VARCHAR(100)
""")
# Test the changes
result = client.execute("SELECT * FROM users LIMIT 1")
print(result.fetchall())
# Compare with original
diffs = client.branch.diff_table(
table='feature_branch.users',
against_table='production.users'
)
print(f"Differences: {diffs}")
# If satisfied, merge back to main
client.branch.merge_table(
source_table='feature_branch.users',
target_table='production.users',
conflict_strategy='accept'
)
# Clean up
client.branch.delete_database_branch('feature_branch')
Use Cases
Development and Testing
Create isolated branches for each feature or bug fix:
from matrixone import Client
client = Client()
client.connect(database='main')
# Create a branch for a new feature
client.branch.create_table_branch(
target_table='feature_users',
source_table='users'
)
# Work on the feature in isolation
client.execute("USE main")
client.execute("""
INSERT INTO feature_users (name, email) VALUES ('test', 'test@example.com')
""")
# Run tests and development
result = client.execute("SELECT * FROM feature_users")
print(result.fetchall())
Schema Experimentation
Test schema changes safely without affecting production:
from matrixone import Client
client = Client()
client.connect(database='production')
# Create a test branch
client.branch.create_database_branch(
target_database='schema_test',
source_database='production'
)
# Switch to test database and experiment with schema changes
client.execute("USE schema_test")
client.execute("ALTER TABLE products ADD COLUMN category_id INT")
client.execute("CREATE INDEX idx_category ON products(category_id)")
# Verify changes work correctly
result = client.execute("SELECT * FROM products LIMIT 1")
print(result.fetchall())
# If successful, apply to production
# If not, simply delete the branch
client.branch.delete_database_branch('schema_test')
Parallel Development
Multiple teams can work on different branches simultaneously:
from matrixone import Client
client = Client()
client.connect(database='main')
# Team A creates their branch
client.branch.create_database_branch(
target_database='team_a_feature',
source_database='main'
)
# Team B creates their branch
client.branch.create_database_branch(
target_database='team_b_feature',
source_database='main'
)
# Both teams work independently
# Changes in one branch don't affect the other
client.execute("USE team_a_feature")
client.execute("INSERT INTO users (name) VALUES ('Team A User')")
client.execute("USE team_b_feature")
client.execute("INSERT INTO users (name) VALUES ('Team B User')")
Comparing and Merging Branches
Compare differences between branches and merge them:
from matrixone import Client, DiffOutput, MergeConflictStrategy
client = Client()
client.connect(database='test')
# Create a branch
client.branch.create_table_branch(
target_table='users_branch',
source_table='users'
)
# Make changes in the branch
client.execute("INSERT INTO users_branch (name) VALUES ('New User')")
# Get count of differences (performance optimized)
diff_count = client.branch.diff_table(
table='users_branch',
against_table='users',
output=DiffOutput.COUNT
)
count_value = diff_count[0][0] if diff_count else 0
print(f"Differences found: {count_value}")
# Get detailed differences
diffs = client.branch.diff_table(
table='users_branch',
against_table='users',
output=DiffOutput.ROWS # or just omit, it's the default
)
print(f"Detailed differences: {len(diffs)}")
# Merge branch back to original (skip conflicts)
client.branch.merge_table(
source_table='users_branch',
target_table='users',
on_conflict=MergeConflictStrategy.SKIP
)
# Or accept source values on conflict
client.branch.merge_table(
source_table='users_branch',
target_table='users',
on_conflict=MergeConflictStrategy.ACCEPT
)
# Clean up
client.branch.delete_table_branch('users_branch')
Point-in-Time Branching
Create branches from specific snapshots:
from matrixone import Client
client = Client()
client.connect(database='production')
# Create a snapshot first
client.snapshot.create_snapshot(
snapshot_name='daily_backup_2024_01_01',
database='production'
)
# Create a branch from the snapshot
client.branch.create_table_branch(
target_table='users_historical',
source_table='users',
snapshot_name='daily_backup_2024_01_01'
)
# Now you have a table as it was at that point in time
result = client.execute("SELECT * FROM users_historical")
print(result.fetchall())
Best Practices
Use Descriptive Names: Name branches clearly to indicate their purpose
# Good client.branch.create_database_branch('feature_payment_integration', 'main') client.branch.create_database_branch('bugfix_user_login_issue', 'main') # Avoid client.branch.create_database_branch('test', 'main') client.branch.create_database_branch('temp', 'main')
Clean Up: Delete branches when they’re no longer needed
# Always clean up after finishing client.branch.delete_database_branch('feature_completed_feature')
Test Before Merging: Always test changes in a branch before applying to main
# Create branch client.branch.create_table_branch('test_branch', 'main_table') # Make and test changes client.execute("INSERT INTO test_branch VALUES (...)") result = client.execute("SELECT * FROM test_branch") # Verify results before merging if result.fetchall(): client.branch.merge_table('test_branch', 'main_table')
Document Changes: Keep track of what changes were made in each branch
Use Consistent Naming: Follow a naming convention for your branches
feature/for new featuresbugfix/for bug fixeshotfix/for urgent fixesexperiment/for experimental work
Performance Considerations
Branches are lightweight and don’t duplicate data
Creating a branch is fast and efficient
Multiple branches can coexist without significant overhead
Diff and merge operations are optimized for performance
Limitations
Branches are isolated - changes in one branch don’t affect others until merged
Merging branches requires explicit operations
Some operations may have branch-specific constraints
API Reference
Enums
DiffOutput Enum
from matrixone import DiffOutput
class DiffOutput(str, Enum):
ROWS = 'rows' # Return detailed differences (default)
COUNT = 'count' # Return only the count of differences
MergeConflictStrategy Enum
from matrixone import MergeConflictStrategy
class MergeConflictStrategy(str, Enum):
SKIP = 'skip' # Skip conflicting rows (default)
ACCEPT = 'accept' # Accept source values on conflict
Table Branch Operations
# Create table branch
client.branch.create_table_branch(
target_table: str,
source_table: str,
snapshot_name: Optional[str] = None
) -> None
# Delete table branch
client.branch.delete_table_branch(table: str) -> None
# Compare tables
client.branch.diff_table(
table: str,
against_table: str,
snapshot_name: Optional[str] = None,
output: DiffOutput = DiffOutput.ROWS
) -> List[Dict[str, Any]]
# Merge tables
client.branch.merge_table(
source_table: str,
target_table: str,
on_conflict: Union[str, MergeConflictStrategy] = "skip"
) -> None
Database Branch Operations
# Create database branch
client.branch.create_database_branch(
target_database: str,
source_database: str
) -> None
# Delete database branch
client.branch.delete_database_branch(database: str) -> None
Simplified API
# Create branch (auto-detects table vs database)
client.branch.create(
target: Union[str, Type],
source: Union[str, Type],
snapshot: Optional[str] = None,
database: bool = False
) -> None
# Delete branch (auto-detects table vs database)
client.branch.delete(
name: Union[str, Type],
database: bool = False
) -> None
# Compare branches
client.branch.diff(
table: Union[str, Type],
against: Union[str, Type],
snapshot: Optional[str] = None,
output: DiffOutput = DiffOutput.ROWS
) -> List[Dict[str, Any]]
# Merge branches
client.branch.merge(
source: Union[str, Type],
target: Union[str, Type],
on_conflict: Union[str, MergeConflictStrategy] = "skip"
) -> None
Statement Builders (SQLAlchemy-Style API)
In addition to the BranchManager API above, the SDK provides SQLAlchemy-style
statement builders that produce SQL strings independently of the client. These work
like select(), insert(), delete(), update() from SQLAlchemy.
from matrixone import (
create_table_branch,
create_database_branch,
delete_table_branch,
delete_database_branch,
diff_table_branch,
merge_table_branch,
)
Creating Branches
# Create table branch from source
stmt = create_table_branch('users_dev').from_table('users')
client.execute(str(stmt))
# With snapshot
stmt = create_table_branch('users_snap').from_table('users', snapshot='snap1')
client.execute(str(stmt))
# Cross-tenant (sys tenant only)
stmt = create_table_branch('users_copy').from_table('users').to_account('tenant1')
client.execute(str(stmt))
# Database branch
stmt = create_database_branch('dev_db').from_database('prod_db')
client.execute(str(stmt))
Deleting Branches
stmt = delete_table_branch('users_dev')
client.execute(str(stmt))
stmt = delete_database_branch('dev_db')
client.execute(str(stmt))
Comparing Branches (Diff)
The diff builder supports all MatrixOne DIFF output options:
# Get all differences
stmt = diff_table_branch('users_dev').against('users')
result = client.execute(str(stmt))
# Count only (performance optimized)
stmt = diff_table_branch('users_dev').against('users').output_count()
result = client.execute(str(stmt))
# Limit rows
stmt = diff_table_branch('users_dev').against('users').output_limit(100)
result = client.execute(str(stmt))
# Export to file
stmt = diff_table_branch('users_dev').against('users').output_file('/tmp/diff.csv')
client.execute(str(stmt))
# With snapshots on both sides
stmt = (
diff_table_branch('t1').snapshot('snap_a')
.against('t2', snapshot='snap_b')
.output_count()
)
client.execute(str(stmt))
Merging Branches
# Merge with skip on conflict (default)
stmt = merge_table_branch('users_dev').into('users')
client.execute(str(stmt))
# Accept source values on conflict
stmt = merge_table_branch('users_dev').into('users').when_conflict('accept')
client.execute(str(stmt))
ORM Model Support
All table builders accept ORM models in place of string table names:
from matrixone.orm import Base, Column, Integer, String
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(100))
stmt = create_table_branch('users_dev').from_table(User)
stmt = diff_table_branch('users_dev').against(User).output_count()
stmt = merge_table_branch('users_dev').into(User).when_conflict('accept')
BranchManager vs Statement Builders
Feature |
BranchManager |
Statement Builders |
|---|---|---|
Execution |
Calls execute internally |
Produces SQL string |
Client dependency |
Requires client |
Independent of client |
DIFF output options |
ROWS, COUNT |
COUNT, LIMIT, FILE, AS |
Cross-tenant (TO ACCOUNT) |
Not supported |
Supported |
Snapshot on base table |
Not supported |
Supported |
See Also
Snapshot and Restore Guide - For point-in-time recovery
Database and Table Cloning Guide - For database cloning
Examples - For more examples