{"record":{"id":"80fe5adb230c6805","repo":"GitoxideLabs/gitoxide","slug":"attaching-requires-detached-head","errorCode":null,"errorMessage":"attaching requires detached HEAD","messagePattern":"attaching requires detached HEAD","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/time_travel.rs","lineNumber":552,"sourceCode":"    bare: bool,\n    revisions: &[OsString],\n    include_worktrees: bool,\n) -> Result<String> {\n    Ok(attach_reporting(repository_path, bare, revisions, include_worktrees)?.0)\n}\n\npub(crate) fn attach_reporting(\n    repository_path: &Path,\n    bare: bool,\n    revisions: &[OsString],\n    include_worktrees: bool,\n) -> Result<(String, Vec<super::undo::RefChange>)> {\n    let repository = open_repository(repository_path, bare, false)\n        .context(\"could not open repository to attach the remembered branch\")?;\n    repository.workdir().context(\"attaching requires a worktree\")?;\n    let head = repository.head().context(\"could not read HEAD before attaching\")?;\n    if !head.is_detached() {\n        anyhow::bail!(\"attaching requires detached HEAD\");\n    }\n    let head_id = head\n        .id()\n        .map(gix::Id::detach)\n        .context(\"attaching requires an existing HEAD commit\")?;\n    drop(head);\n    let remembered = remembered_branch(&repository)?;\n    validate_attach(&repository, head_id, &remembered)?;\n\n    let pins = history::all_pins(&repository)?;\n    let destination_pin = selected_pin(&pins, head_id);\n    let mut ref_changes = Vec::new();\n    let provisional = if remembered.branch_tip != head_id && !contains(&repository, remembered.branch_tip, head_id) {\n        let (pin, created, mut changes) = create_or_reuse_pin_reporting(\n            &repository,\n            Target::Object(remembered.branch_tip),\n            remembered.branch_tip,\n            \"tix attach departure\",","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/time_travel.rs#L534-L570","documentation":"The attach operation can only start from a detached HEAD, but the repository's HEAD currently points at a branch. The library throws this in `attach_reporting` before capturing the head id. Attaching onto a branch checkout would overwrite branch state, so it is refused.","triggerScenarios":"Calling attach (via attach_reporting) on a repo where `repository.head()` is not detached — i.e. HEAD is symbolic to `refs/heads/*` (or unborn on a branch).","commonSituations":"User forgot to detach (e.g. still on `main`); a prior step intended to detach HEAD failed silently; running attach in a fresh clone where a branch is checked out by default.","solutions":["Detach HEAD first, e.g. `git checkout --detach` or `git checkout <commit>`, then retry attach.","In code, verify `repository.head()?.is_detached()` before calling attach.","Use the time-travel `perform` entry point instead if the intent is to switch states rather than attach to a remembered branch."],"exampleFix":"// before\n$ git attach  # HEAD on 'main'\n// after\n$ git checkout --detach  # or git checkout <sha>\n$ git attach","handlingStrategy":"validation","validationCode":"let repo = gix::open(repo_path)?;\nif !repo.head()?.is_detached() {\n    return Err(anyhow!(\"detach HEAD before attaching\"));\n}","typeGuard":"fn head_detached(repo: &gix::Repository) -> bool {\n    repo.head().map(|h| h.is_detached()).unwrap_or(false)\n}","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"attaching requires detached HEAD\") => {\n        // run `git checkout --detach` and retry\n    }\n    other => other?,\n}","preventionTips":["Always detach HEAD as the first step of the attach workflow.","Check `git symbolic-ref -q HEAD` returns non-zero before attaching.","Use perform instead of attach when HEAD is on a branch by design."],"tags":["git","detached-head","precondition","time-travel"],"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"}