{"record":{"id":"ea902f0bf9b51327","repo":"GitoxideLabs/gitoxide","slug":"tree-conflicted","errorCode":null,"errorMessage":"Tree conflicted","messagePattern":"Tree conflicted","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"gitoxide-core/src/repository/merge/commit.rs","lineNumber":80,"sourceCode":"        let tree_id = res\n            .tree\n            .detach()\n            .write(|tree| {\n                written += 1;\n                repo.write(tree)\n            })\n            .map_err(|err| anyhow!(\"{err}\"))?;\n        writeln!(out, \"{tree_id} (wrote {written} trees)\")?;\n    }\n\n    if debug {\n        writeln!(err, \"{:#?}\", res.conflicts)?;\n    }\n    if !has_conflicts {\n        writeln!(err, \"{} possibly resolved conflicts\", res.conflicts.len())?;\n    }\n    if has_unresolved_conflicts {\n        bail!(\"Tree conflicted\")\n    }\n    Ok(())\n}\n\nfn refname_and_commit(\n    repo: &gix::Repository,\n    revspec: BString,\n) -> anyhow::Result<(Option<BString>, gix::hash::ObjectId)> {\n    let spec = repo.rev_parse(revspec.as_bstr())?;\n    let commit_id = spec\n        .single()\n        .context(\"Expected revspec to expand to a single rev only\")?\n        .object()?\n        .peel_to_commit()?\n        .id;\n    let refname = spec.first_reference().map(|r| r.name.shorten().as_bstr().to_owned());\n    Ok((refname, commit_id))\n}","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gitoxide-core/src/repository/merge/commit.rs#L62-L98","documentation":"After performing a tree merge, unresolved conflicts remain: `has_unresolved_conflicts` was true, so the command exits with `Tree conflicted` as a non-zero-error signal. The detailed conflict list is written to stderr just before the bail. This is a controlled outcome of the merge, not an internal error.","triggerScenarios":"Running `gix merge commit` where the merge computation returns conflicts that could not be auto-resolved; the command prints `res.conflicts` to stderr and then bails.","commonSituations":"Merging branches with competing changes to the same paths; history rewrites merged back into a branch; automated merge pipelines hitting real content conflicts.","solutions":["Inspect the conflict list printed on stderr and resolve each path manually","Re-run with different merge options or merge-base inputs","Abort/redo the merge using lower-level gix APIs if partial state was written"],"exampleFix":"// before\n$ gix merge commit --into ref/heads/main other-branch   # exits: Tree conflicted\n// after: resolve conflicts shown on stderr, then commit\n$ gix status && gix merge commit --into ref/heads/main other-branch","handlingStrategy":"try-catch","validationCode":"// pre-check: attempt merge in-memory and inspect conflicts before writing\nlet res = repo.merge_tree(ours, theirs, base, Default::default())?;\nif !res.conflicts.is_empty() {\n    eprintln!(\"{} conflicts expected\", res.conflicts.len());\n}\n","typeGuard":null,"tryCatchPattern":"let exit_code = match result {\n    Err(e) if e.to_string() == \"Tree conflicted\" => {\n        eprintln!(\"merge had unresolved conflicts; see stderr dump\");\n        1\n    }\n    other => { other?; 0 }\n};\n","preventionTips":["Run a dry-run/in-memory merge first and inspect conflicts","Avoid merging branches with known overlapping edits without review","Automate conflict counting via the merge result API before committing"],"tags":["merge","conflict","git"],"backgroundTag":"merge-conflict","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}