{"record":{"id":"d86398349a198053","repo":"GitoxideLabs/gitoxide","slug":"a-detached-checked-out-root-commit-cannot-be-remov","errorCode":null,"errorMessage":"a detached checked-out root commit cannot be removed","messagePattern":"a detached checked-out root commit cannot be removed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/rebase.rs","lineNumber":2929,"sourceCode":"                    continue;\n                }\n                anyhow::bail!(\n                    \"cannot delete {} because another worktree has it checked out\",\n                    expected.name.shorten()\n                );\n            }\n            Some(expected) => Some(expected.new),\n            None => rewritten.get(&old).copied(),\n        };\n        let Some(new) = new else { continue };\n        if worktree_repo.workdir().is_none() && worktree_repo.is_bare() {\n            continue;\n        }\n        let old_tree = worktree_repo.find_commit(old)?.tree_id()?.detach();\n        let new_tree = match new {\n            Some(new) => repo.find_commit(new)?.tree_id()?.detach(),\n            None if worktree_repo.head()?.referent_name().is_some() => repo.empty_tree().id,\n            None => anyhow::bail!(\"a detached checked-out root commit cannot be removed\"),\n        };\n        if old_tree == new_tree {\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(Transition {\n            repo: worktree_repo,\n            workdir,\n            old: old_tree,\n            new: new_tree,\n        });\n    }\n    Ok(out)\n}","sourceCodeStart":2911,"sourceCodeEnd":2947,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/rebase.rs#L2911-L2947","documentation":"When a rebase removes the commit currently checked out in a linked worktree, the worktree must be moved to some replacement tree. If the new commit is `None` (commit removed entirely) and the worktree HEAD is detached (no referent name), there is no branch to re-point and no commit to stay on, so removal of that detached checked-out root commit is refused.","triggerScenarios":"A rebase edit plans `new: None` for a commit `old` that a worktree has checked out; the worktree's `head()?.referent_name()` is `None` (detached HEAD), so neither `repo.find_commit(new)` nor `repo.empty_tree()` fallback applies and the code bails at `gix-tix/src/edit/rebase.rs:2929`.","commonSituations":"Rewriting history that drops the very root/first commit while a CI or scratch worktree sits detached on exactly that commit; force-cleanup scripts that drop root commits of experimental branches checked out detached in secondary worktrees.","solutions":["Attach the worktree's HEAD to a branch (`git switch -c <branch>` or `git switch main`) so the referent-name fallback can move it to the empty tree.","Attach the worktree to a surviving commit outside the rewritten range before running the removal.","Don't remove that root commit — rewrite it instead so `new` is `Some(...)`.","Remove the worktree entirely before the rebase edit."],"exampleFix":"// before: worktree detached on the commit being removed\n// bail: \"a detached checked-out root commit cannot be removed\"\n// after: attach the worktree first\nrun_in(worktree_path, &[\"git\", \"switch\", \"-c\", \"keep-alive\"])?;\nedit.rebase_drop(root_id)?; // now succeeds","handlingStrategy":"validation","validationCode":"if let Some(wt) = worktree_holding(repo, old_commit_id) {\n    let wt_repo = wt.into_repo()?;\n    let detached = wt_repo.head()?.referent_name().is_none();\n    if detached && removal_planned(old_commit_id) {\n        // attach the worktree to a branch before the edit\n    }\n}\n","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never leave CI/scratch worktrees detached on commits inside rewrite ranges","Attach worktrees to branches before dropping root commits","Drop worktrees that are no longer needed before history rewrites"],"tags":["worktree","detached-head","rebase","git"],"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"}