You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The following doc is mostly AI generated. I've made a few tweaks
/etc Three-Way Merge Conflict Resolution
Problem
When upgrading a bootc deployment, /etc undergoes a three-way merge between:
Pristine etc -- The unmodified /etc from the currently booted image.
Current etc -- The live /etc with user modifications.
New etc -- The /etc from the new deployment image.
User modifications (added files, changed permissions, edited content) are preserved
across upgrades. However, a type conflict can occur when a path changes between
file and directory across deployments:
A user-modified file now defaults to a directory in the new image.
A user-modified directory now defaults to a file in the new image.
These conflicts are unmergeable, i.e. the merge cannot reconcile both the user's
modification and the new image's structural change at the same path.
MergeStrategy
MergeStrategy is an enum that controls how unmergeable paths are handled during
the three-way /etc merge. It is defined in the etc-merge crate and derives clap::ValueEnum, Serialize, and Deserialize for use as both a CLI argument
and a configuration value.
Variants
Strategy
Behavior
fail
(Default) Abort the merge. The deployment finalization fails and the system continues booting the current deployment.
skip
Keep the new image's default for conflicting paths. The user's modification at that path is dropped. The merge succeeds.
replace
Keep the user's version. The conflicting entry in the new /etc is removed and replaced with the user's file or directory (including children). The merge succeeds.
Conflict detection
Note
We now detect any conflicts during upgrade/switch and throw an error if we find conflicts
and merge_strategy is Fail
During compute_diff, the check_if_mergable function compares each added or
modified path against the new /etc tree. If a file-vs-directory type mismatch is
found, the path is recorded in diff.unmergable_paths with a human-readable reason.
The merge() function checks this list before proceeding:
With Fail, it bails immediately if any unmergeable paths exist.
With Skip or Replace, it proceeds and handles each conflict according to the
strategy.
Configuration
The merge strategy is determined through the following sources, in order of precedence:
Image authors can ship a default merge strategy inside the container image:
merge_strategy = "skip"
This file is read from the staged deployment's mounted EROFS image at usr/lib/bootc/finalize.toml. It is consulted only when conflicts are detected
and the CLI-provided strategy is fail (the default). If the config file specifies
a non-fail strategy, it overrides the default.
This allows image authors to opt their users into a safe default without requiring
CLI flags on every upgrade.
Finalization
The resolved merge strategy is persisted in the staged deployment JSON file at /run/composefs/staged-deployment. This file is written during write_composefs_state
and read during composefs_backend_finalize.
The resolution flow is:
CLI provides --merge-strategy (default: fail).
During write_composefs_state, if conflicts exist and strategy is fail, check
the image's finalize.toml for a configured strategy.
If a non-fail strategy is found in the config, use it. Otherwise, fail with a
hint about --merge-strategy and finalize.toml.
The resolved strategy is serialized into the staged deployment file.
On reboot, composefs_backend_finalize reads the staged deployment file and
passes the strategy to merge().
The following doc is mostly AI generated. I've made a few tweaks
/etcThree-Way Merge Conflict ResolutionProblem
When upgrading a bootc deployment,
/etcundergoes a three-way merge between:/etcfrom the currently booted image./etcwith user modifications./etcfrom the new deployment image.User modifications (added files, changed permissions, edited content) are preserved
across upgrades. However, a type conflict can occur when a path changes between
file and directory across deployments:
These conflicts are unmergeable, i.e. the merge cannot reconcile both the user's
modification and the new image's structural change at the same path.
MergeStrategy
MergeStrategyis an enum that controls how unmergeable paths are handled duringthe three-way
/etcmerge. It is defined in theetc-mergecrate and derivesclap::ValueEnum,Serialize, andDeserializefor use as both a CLI argumentand a configuration value.
Variants
failskipreplace/etcis removed and replaced with the user's file or directory (including children). The merge succeeds.Conflict detection
Note
We now detect any conflicts during upgrade/switch and throw an error if we find conflicts
and
merge_strategyisFailDuring
compute_diff, thecheck_if_mergablefunction compares each added ormodified path against the new
/etctree. If a file-vs-directory type mismatch isfound, the path is recorded in
diff.unmergable_pathswith a human-readable reason.The
merge()function checks this list before proceeding:Fail, it bails immediately if any unmergeable paths exist.SkiporReplace, it proceeds and handles each conflict according to thestrategy.
Configuration
The merge strategy is determined through the following sources, in order of precedence:
1. CLI option (
--merge-strategy)Available on
bootc upgradeandbootc switch:The
--merge-strategyflag acceptsfail,skip, orreplace. The default isfail.This is implemented via the
EtcMergeStrategyOptsstruct which is flattened intoUpgradeOptsandSwitchOpts.2. Image configuration file (
/usr/lib/bootc/finalize.toml)Image authors can ship a default merge strategy inside the container image:
This file is read from the staged deployment's mounted EROFS image at
usr/lib/bootc/finalize.toml. It is consulted only when conflicts are detectedand the CLI-provided strategy is
fail(the default). If the config file specifiesa non-
failstrategy, it overrides the default.This allows image authors to opt their users into a safe default without requiring
CLI flags on every upgrade.
Finalization
The resolved merge strategy is persisted in the staged deployment JSON file at
/run/composefs/staged-deployment. This file is written duringwrite_composefs_stateand read during
composefs_backend_finalize.The resolution flow is:
--merge-strategy(default:fail).write_composefs_state, if conflicts exist and strategy isfail, checkthe image's
finalize.tomlfor a configured strategy.failstrategy is found in the config, use it. Otherwise, fail with ahint about
--merge-strategyandfinalize.toml.composefs_backend_finalizereads the staged deployment file andpasses the strategy to
merge().