Git-Style Database Branching User Guide
Git-Style Database Branching User Guide
Overview
HeliosDB’s Git-style branching feature allows you to create instant, zero-copy snapshots of your database for development, testing, and debugging. Just like Git branches for code, you can create database branches for data.
Benefits
- Instant branch creation (<1ms) with zero storage overhead
- Test schema changes safely without affecting production
- Debug production issues using time-travel queries
- Develop features in isolation with real production data
- Roll back to any point in time
Key Features
- Copy-on-write (COW) semantics for storage efficiency
- Branch creation at specific LSN or timestamp
- Time-travel queries within branches
- Automatic garbage collection
- Full ACID guarantees per branch
Prerequisites
System Requirements
- HeliosDB v3.2 or later
- PostgreSQL-compatible client
- Sufficient storage for branch divergence (typically 10-20% of main branch)
Required Permissions
-- User needs branch management permissionsGRANT EXECUTE ON FUNCTION heliosdb.create_branch TO developer_role;GRANT EXECUTE ON FUNCTION heliosdb.delete_branch TO developer_role;GRANT SELECT ON heliosdb.branches TO developer_role;Step-by-Step Configuration
1. Enable Branch Support
Edit heliosdb.conf:
branching: enabled: true max_branches: 100 max_depth: 5 default_gc_retention_days: 30 snapshot_path: /var/lib/heliosdb/branchesRestart HeliosDB:
systemctl restart heliosdb2. Verify Installation
-- Check if branching is enabledSELECT heliosdb.branching_enabled();
-- List available branchesSELECT * FROM heliosdb.branches;Expected output:
id | name | parent_id | creation_lsn | current_lsn | created_at | state | depth------+------+-----------+--------------+-------------+------------+--------+------- uuid | main | NULL | 0/0 | 0/5E2A | 2025-... | Active | 0SQL Examples with Explanations
Creating Branches
Basic Branch Creation
-- Create a branch from the current HEAD of mainSELECT heliosdb.create_branch( branch_name => 'feature-auth', parent_branch => 'main');Explanation: Creates an instant snapshot at the current LSN. All data from main is accessible in feature-auth without copying.
Time-Travel Branch
-- Create branch from a specific timestampSELECT heliosdb.create_branch( branch_name => 'debug-session', parent_branch => 'main', from_timestamp => '2025-10-24 14:30:00');Use Case: Debug production issues by recreating database state at the time of the incident.
LSN-Based Branch
-- Create branch from specific LSNSELECT heliosdb.create_branch( branch_name => 'rollback-test', parent_branch => 'main', from_lsn => '0/1234ABCD');Use Case: Precise control for recovery or testing scenarios.
Working with Branches
Switch to a Branch
-- Set session context to work on a specific branchSET heliosdb.current_branch = 'feature-auth';
-- All subsequent queries use this branchINSERT INTO users (email, name) VALUES ('test@example.com', 'Test User');
-- Verify current branchSHOW heliosdb.current_branch;Query Multiple Branches
-- Compare data across branchesSELECT 'main' as branch, COUNT(*) FROM main.usersUNION ALLSELECT 'feature-auth' as branch, COUNT(*) FROM feature_auth.users;Time-Travel Queries
-- Query historical data within a branchSELECT * FROM usersWHERE heliosdb.query_at_lsn('0/1234ABCD');
-- Query data as of specific timestampSELECT * FROM ordersWHERE heliosdb.query_at_timestamp('2025-10-24 12:00:00');Branch Management
List All Branches
SELECT name, parent_id, creation_lsn, current_lsn, EXTRACT(EPOCH FROM (now() - created_at))/3600 as age_hours, state, depthFROM heliosdb.branchesORDER BY created_at DESC;Get Branch Statistics
SELECT heliosdb.branch_stats('feature-auth');Output:
{ "name": "feature-auth", "storage_mb": 2.4, "delta_sstables": 3, "memtable_size_mb": 0.5, "depth": 1, "divergence_percent": 10.2}Delete a Branch
-- Delete a branch (fails if it has children)SELECT heliosdb.delete_branch('feature-auth');
-- Force delete (WARNING: deletes all child branches)SELECT heliosdb.delete_branch('feature-auth', force => true);Common Use Cases
Use Case 1: Schema Migration Testing
-- Create test branchSELECT heliosdb.create_branch('schema-test', 'main');SET heliosdb.current_branch = 'schema-test';
-- Test schema changesALTER TABLE users ADD COLUMN phone VARCHAR(20);CREATE INDEX idx_users_phone ON users(phone);
-- Run queries to validateSELECT COUNT(*) FROM users WHERE phone IS NOT NULL;
-- If successful, apply to mainSET heliosdb.current_branch = 'main';ALTER TABLE users ADD COLUMN phone VARCHAR(20);
-- If failed, simply delete the branchSELECT heliosdb.delete_branch('schema-test');Use Case 2: Production Debugging
-- Someone reports data corruption at 2:30 PMSELECT heliosdb.create_branch( branch_name => 'debug-2025-10-24', parent_branch => 'main', from_timestamp => '2025-10-24 14:30:00');
-- Switch to debug branchSET heliosdb.current_branch = 'debug-2025-10-24';
-- Investigate without affecting productionSELECT * FROM transactionsWHERE status = 'corrupted'AND created_at BETWEEN '2025-10-24 14:00:00' AND '2025-10-24 15:00:00';
-- When done, delete debug branchSELECT heliosdb.delete_branch('debug-2025-10-24');Use Case 3: Feature Development
-- Developer creates feature branchSELECT heliosdb.create_branch('feature-payment-v2', 'main');SET heliosdb.current_branch = 'feature-payment-v2';
-- Develop and test with real dataCREATE TABLE payment_methods ( id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id), method_type VARCHAR(50), details JSONB);
-- Test with production-like dataINSERT INTO payment_methods (user_id, method_type, details)SELECT id, 'credit_card', '{"last4": "1234"}'::jsonbFROM users LIMIT 1000;
-- Run integration tests-- If tests pass, merge changes to main-- If tests fail, delete branch and start overUse Case 4: A/B Testing Queries
-- Create branch for testing query optimizationSELECT heliosdb.create_branch('query-optimization', 'main');SET heliosdb.current_branch = 'query-optimization';
-- Test new index strategyCREATE INDEX CONCURRENTLY idx_orders_complexON orders (user_id, status, created_at);
-- Compare performanceEXPLAIN ANALYZESELECT * FROM ordersWHERE user_id = 123 AND status = 'pending'ORDER BY created_at DESC LIMIT 10;
-- Switch back to main and compareSET heliosdb.current_branch = 'main';EXPLAIN ANALYZESELECT * FROM ordersWHERE user_id = 123 AND status = 'pending'ORDER BY created_at DESC LIMIT 10;Troubleshooting
Issue: Cannot Create Branch
Symptom:
ERROR: Failed to create branch: MaxBranchesReachedSolution:
-- Check current branch countSELECT COUNT(*) FROM heliosdb.branches WHERE state = 'Active';
-- Delete unused branchesSELECT heliosdb.delete_branch(name)FROM heliosdb.branchesWHERE state = 'Active'AND age(now(), created_at) > interval '30 days'AND name LIKE 'debug-%';Issue: Branch Storage Growing
Symptom: Branch using more storage than expected
Solution:
-- Check branch statisticsSELECT name, storage_mb, divergence_percentFROM heliosdb.branch_stats()ORDER BY storage_mb DESC;
-- Manually trigger garbage collectionSELECT heliosdb.gc_branch('feature-auth');
-- Adjust GC retention periodALTER BRANCH 'feature-auth' SET gc_retention_days = 7;Issue: Slow Queries on Branch
Symptom: Queries slower on branch than main
Solution:
-- Check branch depth (deep branches have overhead)SELECT name, depth FROM heliosdb.branches;
-- Create fresh branch from current mainSELECT heliosdb.create_branch('feature-auth-v2', 'main');
-- Migrate work to new branch-- Delete old deep branchSELECT heliosdb.delete_branch('feature-auth');Issue: Cannot Delete Branch with Children
Symptom:
ERROR: Cannot delete branch with childrenSolution:
-- List child branchesSELECT b2.name as child_branchFROM heliosdb.branches b1JOIN heliosdb.branches b2 ON b2.parent_id = b1.idWHERE b1.name = 'feature-parent';
-- Delete children firstSELECT heliosdb.delete_branch('feature-child-1');SELECT heliosdb.delete_branch('feature-child-2');
-- Now delete parentSELECT heliosdb.delete_branch('feature-parent');Performance Tuning Tips
1. Minimize Branch Depth
Keep branches shallow (depth <= 3) for best performance:
-- Avoid: branch → sub-branch → sub-sub-branch-- Prefer: branch → main (depth 1)
-- Recreate from main instead of branching from branchesSELECT heliosdb.create_branch('feature-v2', 'main'); -- Good-- vsSELECT heliosdb.create_branch('feature-v2', 'feature-v1'); -- Avoid2. Regular Garbage Collection
-- Enable automatic GCALTER DATABASE heliosdb SET heliosdb.auto_gc = true;ALTER DATABASE heliosdb SET heliosdb.gc_interval = 3600; -- hourly
-- Manual GC for specific branchSELECT heliosdb.gc_branch('branch-name');3. Limit Branch Lifetime
-- Set expiration on temporary branchesSELECT heliosdb.create_branch( branch_name => 'temp-debug', parent_branch => 'main', expires_at => now() + interval '24 hours');4. Monitor Storage Usage
-- Create monitoring viewCREATE VIEW branch_health ASSELECT name, depth, storage_mb, divergence_percent, age(now(), created_at) as age, CASE WHEN depth > 3 THEN 'Too Deep' WHEN storage_mb > 100 THEN 'Too Large' WHEN age(now(), created_at) > interval '7 days' THEN 'Old' ELSE 'Healthy' END as health_statusFROM heliosdb.branch_stats();
-- Query regularlySELECT * FROM branch_health WHERE health_status != 'Healthy';5. Optimize Write Patterns
-- Batch writes when possibleBEGIN;SET heliosdb.current_branch = 'feature-branch';INSERT INTO users SELECT * FROM staging_users;INSERT INTO orders SELECT * FROM staging_orders;COMMIT;
-- vs multiple small transactions (slower)Best Practices
Branch Naming Convention
-- Use consistent namingfeature/<feature-name> -- Feature developmentbugfix/<bug-id> -- Bug fixesdebug/<date> -- Debug sessionstest/<test-name> -- Testinghotfix/<issue> -- Production hotfixes
-- Examples:SELECT heliosdb.create_branch('feature/user-auth', 'main');SELECT heliosdb.create_branch('debug/2025-10-24', 'main', from_timestamp => '2025-10-24 14:30:00');Branch Lifecycle
-- 1. Create with clear purposeSELECT heliosdb.create_branch('feature/new-api', 'main');
-- 2. Set contextSET heliosdb.current_branch = 'feature/new-api';
-- 3. Do work-- ... development ...
-- 4. Test thoroughly-- ... testing ...
-- 5. Merge to main (application-level merge)-- Copy successful changes to main
-- 6. Clean upSELECT heliosdb.delete_branch('feature/new-api');Security Considerations
-- Restrict branch creation in productionREVOKE EXECUTE ON FUNCTION heliosdb.create_branch FROM public;GRANT EXECUTE ON FUNCTION heliosdb.create_branch TO admin_role;
-- Audit branch operationsCREATE TABLE branch_audit ( operation TEXT, branch_name TEXT, user_name TEXT, timestamp TIMESTAMPTZ DEFAULT now());
-- Log all branch operationsCREATE OR REPLACE FUNCTION log_branch_operation()RETURNS TRIGGER AS $$BEGIN INSERT INTO branch_audit (operation, branch_name, user_name) VALUES (TG_OP, NEW.name, current_user); RETURN NEW;END;$$ LANGUAGE plpgsql;Resource Limits
-- Set per-user branch limitsALTER ROLE developer_user SET heliosdb.max_branches = 5;
-- Set organization-wide limitsALTER DATABASE heliosdb SET heliosdb.max_total_branches = 100;
-- Monitor quota usageSELECT current_user, COUNT(*) as branch_count, current_setting('heliosdb.max_branches')::int as limitFROM heliosdb.branchesWHERE owner = current_userGROUP BY current_user;Integration with CI/CD
GitHub Actions Example
name: Database Testson: [pull_request]jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2
- name: Create test branch run: | psql $DATABASE_URL -c " SELECT heliosdb.create_branch( 'ci-test-${{ github.run_id }}', 'main' ); "
- name: Run migrations run: | export HELIOSDB_BRANCH="ci-test-${{ github.run_id }}" ./migrate.sh
- name: Run tests run: | export HELIOSDB_BRANCH="ci-test-${{ github.run_id }}" npm test
- name: Cleanup if: always() run: | psql $DATABASE_URL -c " SELECT heliosdb.delete_branch('ci-test-${{ github.run_id }}'); "Monitoring and Observability
Key Metrics to Monitor
-- Branch count over timeSELECT COUNT(*) as active_branchesFROM heliosdb.branchesWHERE state = 'Active';
-- Total branch storageSELECT SUM(storage_mb) as total_branch_storage_mbFROM heliosdb.branch_stats();
-- Branch age distributionSELECT CASE WHEN age < interval '1 day' THEN '<1 day' WHEN age < interval '7 days' THEN '1-7 days' WHEN age < interval '30 days' THEN '7-30 days' ELSE '>30 days' END as age_bucket, COUNT(*) as branch_countFROM ( SELECT age(now(), created_at) as age FROM heliosdb.branches) subGROUP BY age_bucket;Prometheus Metrics
# Add to prometheus.ymlscrape_configs: - job_name: 'heliosdb_branches' static_configs: - targets: ['localhost:9090'] metrics_path: '/metrics/branches'Exported metrics:
heliosdb_branches_total: Total number of branchesheliosdb_branch_storage_bytes: Storage per branchheliosdb_branch_depth: Branch depthheliosdb_branch_age_seconds: Age of each branch
Advanced Topics
Cross-Branch Queries
-- Join data across branchesSELECT m.user_id, m.balance as main_balance, f.balance as feature_balance, f.balance - m.balance as differenceFROM main.accounts mJOIN feature_payment.accounts f ON m.user_id = f.user_idWHERE f.balance != m.balance;Branch Merging Strategies
While HeliosDB doesn’t have automatic merge, you can implement merge logic:
-- Application-level mergeBEGIN;-- 1. Switch to mainSET heliosdb.current_branch = 'main';
-- 2. Apply changes from feature branchINSERT INTO usersSELECT * FROM feature_auth.usersWHERE id NOT IN (SELECT id FROM users);
UPDATE users uSET email = f.email, name = f.nameFROM feature_auth.users fWHERE u.id = f.id AND (u.email != f.email OR u.name != f.name);
COMMIT;
-- 3. Delete feature branchSELECT heliosdb.delete_branch('feature-auth');Conclusion
Git-style branching in HeliosDB provides powerful capabilities for development, testing, and debugging with minimal storage overhead and instant creation times. By following the best practices in this guide, you can safely experiment with your database while maintaining production stability.
For more information, see:
- API Reference:
/docs/api/branching.md - Architecture Details:
/docs/architecture/BRANCHING_ARCHITECTURE.md - Performance Tuning:
/docs/performance/branching-optimization.md