{"record":{"id":"57e880e1993dc7ba","repo":"GitoxideLabs/gitoxide","slug":"undo-redo-cannot-delete-a-worktree-head","errorCode":null,"errorMessage":"undo/redo cannot delete a worktree HEAD","messagePattern":"undo/redo cannot delete a worktree HEAD","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/undo.rs","lineNumber":426,"sourceCode":"    }\n\n    let mut out = Vec::new();\n    let mut seen = HashSet::new();\n    for worktree_repo in repos {\n        if !seen.insert(worktree_repo.git_dir().to_owned()) {\n            continue;\n        }\n        let head = worktree_repo.head().context(\"could not inspect a worktree HEAD\")?;\n        let old_id = head.id().map(gix::Id::detach);\n        let raw_head = worktree_repo\n            .find_reference(\"HEAD\")\n            .context(\"could not read a worktree HEAD reference\")?;\n        let raw_head = state_from_target_ref(raw_head.target());\n        let current = gix::path::realpath(worktree_repo.git_dir())\n            .context(\"could not resolve an affected worktree Git directory\")?\n            == current_git_dir;\n        let projected_head = projected_ref_state(&worktree_repo, b\"HEAD\".as_bstr(), &raw_head, changes, current)?;\n        ensure!(\n            projected_head != State::Missing,\n            \"undo/redo cannot delete a worktree HEAD\"\n        );\n        let new_id = resolve_state(&worktree_repo, &projected_head, changes, current, &mut HashSet::new())?;\n        let old = tree_id(&worktree_repo, old_id).context(\"could not inspect the current worktree tree\")?;\n        let new = tree_id(&worktree_repo, new_id).context(\"could not inspect the destination worktree tree\")?;\n        if old == new || (worktree_repo.workdir().is_none() && worktree_repo.is_bare()) {\n            continue;\n        }\n        let workdir = worktree_repo\n            .workdir()\n            .filter(|path| path.is_dir())\n            .context(\"an affected worktree is inaccessible\")?\n            .to_owned();\n        out.push(WorktreeTransition {\n            repo: worktree_repo,\n            workdir,\n            old,","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/undo.rs#L408-L444","documentation":"During undo/redo, `worktree_transitions` projects what each affected worktree's HEAD will look like after applying the ref changes. If the projection yields `State::Missing` for a worktree HEAD, applying the changes would leave that worktree without a valid HEAD, which is unsupported, so the operation aborts with this error before touching anything.","triggerScenarios":"Running undo or redo (`apply_with_worktrees` -> `worktree_transitions`) when the recorded changes delete or move the ref(s) that a worktree's HEAD (symbolic or direct) resolves through, such that the projected HEAD state becomes Missing.","commonSituations":"Undoing a change that deleted a branch which is another worktree's HEAD; deleting branches checked out in linked worktrees then trying to undo back across that deletion.","solutions":["Point the affected worktree's HEAD at a branch that survives the undo/redo (e.g. `git -C <worktree> switch <other-branch>`).","Detach the worktree HEAD (`git switch --detach <commit>`) if the underlying branch must remain un-undoable.","Remove the worktree (`git worktree remove`) if it is no longer needed.","Re-order operations so the worktree HEAD is first re-created before undoing past its deletion."],"exampleFix":"// before: undo deletes the branch worktree B has checked out -> HEAD would go Missing\nrepo.undo()?;\n// after: re-point worktree B's HEAD first\n// git -C ../wt-b switch main\nrepo.undo()?;","handlingStrategy":"validation","validationCode":"// before undo, ensure no worktree HEAD resolves solely through refs the change deletes\nfor wt in affected_worktrees {\n    let head = wt.head_ref_name();\n    let dies = changes.iter().any(|c| &c.name == head && c.after == State::Missing);\n    if dies { anyhow::bail!(\"worktree {wt:?} HEAD would be deleted; re-point it first\"); }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Don't delete branches that are checked out in any worktree.","Detach or re-point worktree HEADs before operations that delete their branch.","List worktrees (`git worktree list`) and their HEADs before undo/redo."],"tags":["git","worktree","head","undo"],"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-15T23:17:13.987Z"}