{"record":{"id":"99aeaedad2b9306f","repo":"gitbutlerapp/gitbutler","slug":"re-merging-the-conflicting-trees-of-commit-commit","errorCode":null,"errorMessage":"Re-merging the conflicting trees of commit {commit_id} yielded no conflicts to resolve","messagePattern":"Re-merging the conflicting trees of commit (.+?) yielded no conflicts to resolve","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-api/src/resolve/context.rs","lineNumber":168,"sourceCode":"    let repo = repo.clone().for_tree_diffing()?;\n    // Merge without favoring a side to reproduce the actual conflicts, and\n    // force diff3-style markers with the sentinel labels so every hunk carries\n    // the common ancestor and marker lines are exactly known strings.\n    let mut options: gix::merge::plumbing::tree::Options = repo.tree_merge_options()?.into();\n    options.blob_merge.text.conflict = gix::merge::blob::builtin_driver::text::Conflict::Keep {\n        style: gix::merge::blob::builtin_driver::text::ConflictStyle::Diff3,\n        marker_size: 7.try_into().expect(\"non-zero constant\"),\n    };\n    let mut outcome = repo.merge_trees(base, ours, theirs, merge_labels(), options.into())?;\n    let merged_tree_id = outcome.tree.write()?.detach();\n\n    let mut index = repo.index_from_tree(&merged_tree_id)?;\n    if !outcome.index_changed_after_applying_conflicts(\n        &mut index,\n        gix::merge::tree::TreatAsUnresolved::git(),\n        gix::merge::tree::apply_index_entries::RemovalMode::Mark,\n    ) {\n        bail!(\n            \"Re-merging the conflicting trees of commit {commit_id} yielded no conflicts to resolve\"\n        );\n    }\n\n    let mut sides_by_path: std::collections::BTreeMap<BString, ConflictSides> = Default::default();\n    for entry in index.entries() {\n        use gix::index::entry::Stage;\n        let sides = sides_by_path\n            .entry(entry.path(&index).to_owned())\n            .or_default();\n        match entry.stage() {\n            Stage::Unconflicted => continue,\n            Stage::Base => sides.base = true,\n            Stage::Ours => sides.ours = true,\n            Stage::Theirs => sides.theirs = true,\n        }\n    }\n    sides_by_path.retain(|_, sides| sides.base || sides.ours || sides.theirs);","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-api/src/resolve/context.rs#L150-L186","documentation":"build_request() confirmed the commit is conflicted (three trees available), then re-merges base/ours/theirs with diff3 markers and applies the conflicts to a fresh index. If that application reports no changed entries, the re-merge produced nothing addressable - inconsistent with the conflicted shape detected earlier - so it bails defensively rather than fabricate an empty resolution request.","triggerScenarios":"Rare: repo configuration makes the re-merge fully clean, e.g. custom merge drivers wired through .gitattributes/drivers that auto-resolve when gix replays the merge with GitButler's labels, or degenerate rename/splice histories where the second merge agrees everywhere.","commonSituations":"Repos with custom merge drivers (union drivers, lockfile drivers) active during the re-merge; exotic conflict shapes produced by external tools; essentially never on default git configuration.","solutions":["Resolve this commit manually (edit mode or outside the API) - the request cannot be built","Check .gitattributes and gitconfig for custom merge drivers that interfere with the re-merge","If it reproduces with stock merge config, report it with the commit shape"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await api.resolveCommitConflictHunks(commitId, specs);\n} catch (err) {\n  if (String(err).includes('yielded no conflicts to resolve')) {\n    routeToManualResolution(commitId); // internal inconsistency; not retryable via this API\n  } else throw err;\n}","preventionTips":["Check .gitattributes/gitconfig for custom merge drivers before using the resolve APIs on that repo","Treat this as non-retryable through the API - the request itself cannot be built","Keep the commit around when it reproduces; it is a bug-report-grade state"],"tags":["conflict-resolution","merge","internal-invariant","resolve-api"],"backgroundTag":"no-conflicts-to-resolve","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}