Recommendation for config struct overrides

I have a config struct that comes up twice in my config structure. Once as git_defaults in GlobalConfig and once as git_overrides in RepoConfig.

I'm running into a problem though because the git_defaults and git_overrides structs should be serialized differently.

I need the git_defaults struct to be fully populated (no Option<> fields) and use #[serde(default)], since this struct contains the fallback configuration:

#[derive(..., Serialize, Deserialize)]
#[serde(default)]
struct Git {
  auto_push: bool,
  working_branch: String,
}

impl Default for Git {
  ...
}

git_overrides however needs to explicitly show whether a field was overridden:

// notice the derive(Default) will lead to all fields
// being `None` by default ("not overridden")
#[derive(..., Serialize, Deserialize, Default)]
struct GitOverrides {
  auto_push: Option<bool>,
  working_branch: Option<String>,
}

Since this leads to all "overridable" config structs to be duplicated in code, I hate it. My current thinking is to write a proc macro that takes my normal Git struct (and other overridable structs) and creates their {}Overrides variant.

Any better ideas of how to do this without codegen?

Thinking about this some more, I believe the better solution might be to only have these values once in my code and handle overrides with custom deserialization...

I assume you only need struct with no options in the end to perform your program logic. And you need struct with options only to handle partial overrides.
Take a look at figment. It (de)serializes lousy data from different config sources and then allows to get out complete structs with affordances for overrides and ability to tell where those overrides come from.

I've hacked my way through this sort of thing before by first deserializing to untyped Values then merging before then deserializing again to the typed structure, which also lets you use generic merging logic. You can't use this if you want to round-trip the values back out easily, of course, but that also brings a whole suite of horrifying problems to consider if you want to do it well.

You might want to take a look into the struct-patch crate. At least it sounds like that's what you are planning to do.

Thanks very much for the recommendations. struct-patch looks similar to what i was planning on creating myself and figment has error handling looking so neat I'll definetly look into it.