Conflict resolution¶
The upgrade engine detects when users have modified managed files and provides three strategies for handling conflicts.
How conflicts are detected¶
When a file is tracked with full or sections strategy, the engine stores a SHA-256 hash of the file contents in .bluefox. Before applying an operation, it compares the current file hash against the stored hash.
If they differ, the user has modified the file since the last upgrade.
Checking before execution¶
conflicts = check_conflicts(plan, project_dir, dotfile)
for report in conflicts:
print(f"{report.conflict.message}")
This lets you inspect conflicts before deciding how to proceed.
Conflict modes¶
Abort (default)¶
Raises UpgradeError on the first conflict. No files are modified.
Skip¶
Skips conflicting operations and applies the rest. User edits are preserved.
result = execute_upgrade(plan, project_dir, dotfile, render_template, skip_conflicts=True)
for op, conflict in result.skipped:
print(f"Skipped: {op.describe()} — {conflict.message}")
Force¶
Backs up the user-modified file to .bluefox-backups/<timestamp>/, then overwrites.
result = execute_upgrade(plan, project_dir, dotfile, render_template, force=True)
for path, backup_path in result.backed_up:
print(f"Backed up {path} → {backup_path}")
What doesn't conflict¶
- Structured files (
pyproject.toml) — dependency operations modify specific fields, not the whole file. No hash tracking. - New files (
CreateFile) — only conflicts if the target path already exists. - Section updates (
UpdateSection) — conflict detection is based on the full file hash, so edits outside markers still trigger a conflict.