{"record":{"id":"4653a7912de1e1db","repo":"GitoxideLabs/gitoxide","slug":"head-moved-to-an-unrelated-commit-while-resolving","errorCode":null,"errorMessage":"HEAD moved to an unrelated commit while resolving the conflict; return to the conflict checkout or exit","messagePattern":"HEAD moved to an unrelated commit while resolving the conflict; return to the conflict checkout or exit","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/lib.rs","lineNumber":4428,"sourceCode":"        \"HEAD attachment changed while resolving the conflict; return to the conflict checkout or exit\"\n    );\n    let replacement = head\n        .id()\n        .map(gix::Id::detach)\n        .context(\"HEAD became unborn while resolving the conflict\")?;\n    drop(head);\n    if replacement == state.commit {\n        return Ok(ExternalConflictResolution::Current);\n    }\n\n    let replacement_commit = repository\n        .find_commit(replacement)\n        .context(\"the replacement HEAD is not a commit\")?\n        .decode()\n        .context(\"could not decode the replacement HEAD commit\")?\n        .into_owned()\n        .context(\"could not own the replacement HEAD commit\")?;\n    anyhow::ensure!(\n        replacement_commit.parents.as_slice() == expected.parents,\n        \"HEAD moved to an unrelated commit while resolving the conflict; return to the conflict checkout or exit\"\n    );\n    let index = repository\n        .open_index()\n        .context(\"could not inspect the conflict index\")?;\n    if index\n        .entries()\n        .iter()\n        .any(|entry| entry.stage() != gix::index::entry::Stage::Unconflicted)\n    {\n        return Ok(ExternalConflictResolution::Changed);\n    }\n    if edit::create::index_tree(&repository, &index)? != replacement_commit.tree {\n        return Ok(ExternalConflictResolution::Changed);\n    }\n\n    let name = expected","sourceCodeStart":4410,"sourceCodeEnd":4446,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/lib.rs#L4410-L4446","documentation":"During external conflict finalization, HEAD's current commit (the replacement) is decoded and its parent list is compared with `expected.parents`. If the parent list differs, HEAD was moved to an unrelated commit while the conflict was open, so finalization is refused.","triggerScenarios":"HEAD's commit at finalize time has parents != those recorded when the conflict checkout happened — e.g. an amend, rebase, or new commit created on the branch during resolution, then HEAD points at a commit whose ancestry diverges.","commonSituations":"User runs `git commit --amend`, `git pull --rebase`, or makes a new commit in another terminal while the external merge-tool conflict resolution is pending.","solutions":["Reset the branch back to a commit with the expected parents (`git reset --hard <expected-parent>` plus the replacement) before resuming.","Return to the conflict checkout state and redo the resolution to refresh `expected`.","Don't amend/commit/rebase on the branch while an external conflict resolution is pending."],"exampleFix":"// before\nanyhow::ensure!(\n    replacement_commit.parents.as_slice() == expected.parents,\n    \"HEAD moved to an unrelated commit while resolving the conflict; return to the conflict checkout or exit\"\n);\n// after\nif replacement_commit.parents.as_slice() != expected.parents {\n    tracing::warn!(\"HEAD ancestry changed during conflict resolution; refreshing expected state\");\n    return Err(ConflictStale::Retry.required());\n}","handlingStrategy":"validation","validationCode":"let head_commit = repo.head()?.id().context(\"unborn HEAD\")?.find_commit()?.decode()?.into_owned()?;\nif head_commit.parents != expected.parents {\n    eprintln!(\"HEAD ancestry changed; restart the conflict resolution\");\n    return;\n}","typeGuard":"fn parents_unchanged(c: &gix_object::Commit, expected: &[gix::ObjectId]) -> bool {\n    c.parents.as_slice() == expected\n}","tryCatchPattern":"match finalize() {\n    Err(e) if e.to_string().contains(\"unrelated commit\") => restart_conflict_resolution(),\n    other => other,\n}","preventionTips":["Avoid amend/rebase/new commits on the branch while conflicts are pending.","Snapshot expected.parents at checkout and re-check before every mutation.","Use a dedicated worktree for conflict resolution to isolate it from other work."],"tags":["git","head","commit-parents","conflict"],"backgroundTag":"invalid-state-transition","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}