{"record":{"id":"266a6fda66c99fd1","repo":"gitbutlerapp/gitbutler","slug":"operation-not-possible-while-head-is-detached","errorCode":null,"errorMessage":"Operation not possible while HEAD is detached","messagePattern":"Operation not possible while HEAD is detached","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/upstream_integration.rs","lineNumber":187,"sourceCode":"///\n/// With `single_branch_mode`, a managed workspace whose applied stacks were all integrated is\n/// replaced by a checked-out canned branch at the target tip. Otherwise the emptied managed\n/// workspace stays checked out, reparented onto the target.\n#[allow(clippy::too_many_arguments)]\npub fn integrate_upstream_with_hints<'ws, 'meta, M: RefMetadata>(\n    workspace: &'ws mut but_graph::Workspace,\n    meta: &'meta mut M,\n    project_meta: ProjectMeta,\n    repo: &gix::Repository,\n    db: &'meta mut but_db::DbHandle,\n    updates: Vec<BottomUpdate>,\n    review_hints: &[ReviewIntegrationHint],\n    single_branch_mode: bool,\n) -> Result<IntegrateUpstreamOutcome<'ws, 'meta, M>> {\n    if matches!(workspace.kind, but_graph::workspace::WorkspaceKind::AdHoc)\n        && workspace.ref_name().is_none()\n    {\n        bail!(\"Operation not possible while HEAD is detached\");\n    }\n\n    let mut ws_meta = workspace.metadata.clone();\n    let target_sha = project_meta\n        .target_commit_id\n        .context(\"Cannot update a workspace without a target sha\")?;\n    let target_ref = workspace\n        .target_ref\n        .clone()\n        .context(\"Cannot update a workspace with no target ref\")?;\n    let target_ref_commit = repo.find_reference(&target_ref.ref_name)?.id();\n\n    let entrypoint = workspace.graph.entrypoint()?;\n    let head_commit = entrypoint\n        .commit()\n        .context(\"Cannot update workspace without head commit\")?;\n    let head_commit = repo.find_commit(head_commit.id)?;\n    let head_commit_id = head_commit.id;","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-workspace/src/upstream_integration.rs#L169-L205","documentation":"Thrown by integrate_upstream_with_hints when HEAD is detached such that the workspace is Ad-hoc and has no ref name. Upstream integration operates on a named workspace/stack ref, so with no branch checked out there is nothing to integrate into. The library refuses rather than guessing a ref.","triggerScenarios":"Calling integrate_upstream (or its hint-based variant) while the repository is in detached-HEAD state (e.g. after checkout of a commit), producing WorkspaceKind::AdHoc with workspace.ref_name() == None.","commonSituations":"CI pipelines that check out a raw commit SHA; users who ran `git checkout <sha>` or a bisect; tools that create worktrees in detached state and then attempt stack integration.","solutions":["Check out a branch first (git switch <branch>) before integrating upstream changes.","In code, detect detached HEAD (workspace.kind == AdHoc && ref_name().is_none()) and fail fast with a clear user instruction.","For CI, create a branch at the checked-out commit before invoking integration."],"exampleFix":"# before (detached)\ngit checkout 1a2b3c4\nbut integrate  # fails\n\n# after\ngit switch -c work-branch  # or: git switch main\nbut integrate","handlingStrategy":"validation","validationCode":"fn can_integrate(workspace: &Workspace) -> bool {\n    !(workspace.kind == but_graph::workspace::WorkspaceKind::AdHoc\n        && workspace.ref_name().is_none())\n}","typeGuard":"fn workspace_ref(ws: &Workspace) -> Option<&gix::refs::FullNameRef> {\n    (ws.kind != WorkspaceKind::AdHoc).then_some(()).and(ws.ref_name())\n}","tryCatchPattern":"if let Err(e) = integrate_upstream(...) {\n    if e.to_string().contains(\"HEAD is detached\") {\n        eprintln!(\"checkout a branch before integrating\");\n    } else { return Err(e); }\n}","preventionTips":["Detect detached HEAD at app startup and prompt the user to create/switch to a branch","In CI, create a branch at the fetched commit before any integration step","Check workspace.kind and ref_name() before invoking upstream integration APIs"],"tags":["git","detached-head","workspace"],"backgroundTag":"invalid-state-transition","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}