GitoxideLabs/gitoxide · error

parent-match assures this

Error message

parent-match assures this

What it means

This `unreachable!()` in `gix-merge`'s three-way tree merge fires when a conflict-side change is neither a Modification nor a Deletion while applying an ours-changed/theirs-deleted resolution. The enclosing code assumes the parent matching logic guarantees only those two `Change` shapes can occur here.

Solutions

  1. Report the panic upstream with the two trees and ancestor that reproduce the merge.
  2. Update `gix-merge` to the latest patch version in case the parent-matching invariant was fixed.
  3. If you maintain the code, replace the wildcard arm with an explicit error or handle `Change::Addition` deliberately.

Example fix

// before
_ => unreachable!("parent-match assures this"),
// after
other => return Err(message!("unexpected change {other:?} during ours-modified/theirs-deleted resolution"))
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate inputs are complete trees before merging
// gix_merge::tree(...) requires ancestor, ours, theirs tree objects resolvable in the object store

Try / catch

// Panics propagate; run merges behind catch_unwind or in a worker process.
let result = std::panic::catch_unwind(|| gix_merge::tree(...));

Prevention

When it happens

Trigger: Calling `gix_merge::tree(...)` (merge) with an index or tree state where a change entry for the current location is `Addition` instead of Modification/Deletion — i.e. a broken parent-child correspondence between merged trees.

Common situations: Practically unreachable; would indicate a bug in the change enumeration during a merge involving deeply nested paths where one side deleted a directory.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/ffbd613416751d5c. Report an issue: GitHub.

Appendix: source

Thrown at gix-merge/src/tree/function/resolve.rs:1070

                                    ];
                                    match resolve_tree_conflicts {
                                        None => {
                                            editor.upsert(toc(location), entry_mode.kind(), *id)?;
                                        }
                                        Some(ResolveWith::Ours) => {
                                            let ours = match outer_side {
                                                Original => ours,
                                                Swapped => theirs,
                                            };

                                            match ours {
                                                Change::Modification { .. } => {
                                                    editor.upsert(toc(location), entry_mode.kind(), *id)?;
                                                }
                                                Change::Deletion { .. } => {
                                                    editor.remove(toc(location))?;
                                                }
                                                _ => unreachable!("parent-match assures this"),
                                            }
                                        }
                                        Some(ResolveWith::Ancestor) => {}
                                    }
                                    should_fail_on_conflict(Conflict::without_resolution(
                                        ResolutionFailure::OursModifiedTheirsDeleted,
                                        (ours, theirs, side, outer_side),
                                        entries,
                                    ))
                                };
                                let deletion_was_applied = match resolve_tree_conflicts {
                                    None => deletion_replaced_by_directory,
                                    Some(ResolveWith::Ours) => side.to_global(outer_side).is_swapped(),
                                    Some(ResolveWith::Ancestor) => false,
                                };
                                if deletion_was_applied {
                                    match side {
                                        Original => theirs_disposition = ChangeDisposition::Applied,

View on GitHub (pinned to e73179060b)