3-Way Merge
How template updates work with 3-way merging
3-Way Merge
CyanPrint uses 3-way merge to update templates while preserving user modifications.
What is 3-Way Merge?
3-way merge combines three versions of files:
- Base - Original generated files
- Ours - User modifications
- Theirs - New template version
Why 3-Way Merge?
When users modify generated projects, naive updates would:
- Lose user changes (overwrite)
- Miss template improvements (skip)
3-way merge:
- Preserves user modifications
- Incorporates template updates
- Flags conflicts for resolution
How It Works
Generation Tracking
Each generation stores its base state:
Update Process
Read base
Load original generated files
Read ours
Load current project files
Generate theirs
Run new template version
Merge
Combine all three versions
Report conflicts
Flag unresolved changes
Merge Algorithm
Example Scenario
Original Generation (v1.0)
Base README.md:
# my-projectA sample project.
User Modification
User changes README.md:
# my-projectA sample project.## Features- Feature 1- Feature 2
Template Update (v2.0)
New template generates:
# my-projectA sample project.## Installationnpm install
3-Way Merge Result
# my-projectA sample project.## Installationnpm install## Features- Feature 1- Feature 2
Conflict Detection
When both user and template change the same content:
User Change
# My Awesome Project
Template Change
# my-project[]
Conflict
<<<<<<< OURS# My Awesome Project=======# my-project[]>>>>>>> THEIRS
Determinism and Updates
The deterministic state system ensures IDs remain consistent across updates:
// v1.0 generationconst projectId = d.get('project-id', () => crypto.randomUUID());// Returns: "abc-123"// v2.0 update - same key returns same valueconst projectId = d.get('project-id', () => crypto.randomUUID());// Returns: "abc-123" - same!
This allows:
- Database migrations to work
- API contracts to remain valid
- References to stay consistent
Update Command
# Update to latest versioncyanprint update ./my-project# Update to specific versioncyanprint update ./my-project myorg/template:2.0.0# Preview changes without applyingcyanprint update ./my-project --dry-run
Best Practices
For Template Authors
- Minimize breaking changes - Keep file structure stable
- Use semantic versioning - Major versions for breaking changes
- Document changes - Help users understand updates
- Test updates - Verify merge behavior
For Users
- Commit before updating - Easy rollback if needed
- Review conflicts carefully - Don't blindly accept changes
- Test after updates - Verify everything still works
- Keep base files - Don't delete
.cyan/
Limitations
3-way merge works best with text files (not binaries), line-based changes, and small modifications.
It may struggle with large reorganizations, binary file changes, and complex refactors.