{"record":{"id":"7855f77846b062bb","repo":"GitoxideLabs/gitoxide","slug":"head-no-longer-directly-references-its-replacement","errorCode":null,"errorMessage":"HEAD no longer directly references its replacement commit","messagePattern":"HEAD no longer directly references its replacement commit","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/lib.rs","lineNumber":4450,"sourceCode":"    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\n        .reference\n        .clone()\n        .unwrap_or_else(|| \"HEAD\".try_into().expect(\"valid reference name\"));\n    anyhow::ensure!(\n        edit::undo::state(&repository, name.as_ref())? == edit::undo::State::Object(replacement),\n        \"HEAD no longer directly references its replacement commit\"\n    );\n    let finalized = if edit::rebase::is_pending(&replacement_commit) {\n        drop(index);\n        let graph = edit::loaded_graph(&repository).context(\"could not load history to finalize the external amend\")?;\n        let outcome = edit::head::amend_index_reporting(repository, &graph)\n            .context(\"could not finalize the externally amended pending commit\")?\n            .context(\"the externally amended pending commit was not finalized\")?;\n        let selected = outcome\n            .selected\n            .context(\"finalizing the externally amended conflict did not select its result\")?;\n        Some((selected, outcome.ref_changes))\n    } else {\n        None\n    };\n    let accepted = state.commit;\n    let mut state = pending","sourceCodeStart":4432,"sourceCodeEnd":4468,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/lib.rs#L4432-L4468","documentation":"Final check during external conflict finalization: the recorded undo state of HEAD's referent must be `State::Object(replacement)`, i.e. HEAD directly references the replacement commit. If undo state reports anything else (symbolic elsewhere, unborn, different object), HEAD no longer directly references the replacement and finalization aborts.","triggerScenarios":"`edit::undo::state(&repository, name)` != `State::Object(replacement)` — HEAD was detached, re-pointed, or its undo bookkeeping was overwritten between the parent checks and finalization.","commonSituations":"Concurrent `git reset`/`git checkout` during resolution; stale undo state after a crash; running the finalize step twice where the first pass mutated undo bookkeeping.","solutions":["Re-point the reference at the replacement commit (`git update-ref <name> <replacement>`) so the direct object reference is restored.","Re-run the conflict checkout to rebuild consistent undo state, then finalize again.","Check for concurrent git processes mutating refs during finalization."],"exampleFix":"// before\nanyhow::ensure!(\n    edit::undo::state(&repository, name.as_ref())? == edit::undo::State::Object(replacement),\n    \"HEAD no longer directly references its replacement commit\"\n);\n// after\nif edit::undo::state(&repository, name.as_ref())? != edit::undo::State::Object(replacement) {\n    repository.reference(name.as_bstr(), replacement, gix::refs::transaction::PreviousValue::Any)?;\n}","handlingStrategy":"validation","validationCode":"let state = edit::undo::state(&repo, name.as_bstr())?;\nif state != edit::undo::State::Object(replacement) {\n    eprintln!(\"HEAD does not directly reference the replacement; restoring...\");\n}","typeGuard":"fn head_directly_at(repo: &gix::Repository, name: &gix::refs::FullNameRef, replacement: gix::ObjectId) -> bool {\n    matches!(edit::undo::state(repo, name).ok().as_ref(), Some(edit::undo::State::Object(id)) if *id == replacement)\n}","tryCatchPattern":"if edit::undo::state(&repo, name.as_bstr())? != edit::undo::State::Object(replacement) {\n    restore_reference(name, replacement)?; // then retry finalize\n}","preventionTips":["Keep reference updates and undo-state writes atomic.","Guard against concurrent git processes during finalization.","Verify undo state right before each finalize step, not only at entry."],"tags":["git","head","reference","undo-state"],"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"}