Skip to content

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.

result = execute_upgrade(plan, project_dir, dotfile, render_template)

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.