{"record":{"id":"85c757bdda8a9ffb","repo":"affaan-m/ECC","slug":"cannot-reset-a-staged-hunk-while-the-file-also-has","errorCode":null,"errorMessage":"cannot reset a staged hunk while the file also has unstaged changes; unstage it first","messagePattern":"cannot reset a staged hunk while the file also has unstaged changes; unstage it first","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"ecc2/src/worktree/mod.rs","lineNumber":441,"sourceCode":"    )\n}\n\npub fn reset_hunk(\n    worktree: &WorktreeInfo,\n    entry: &GitStatusEntry,\n    hunk: &GitPatchHunk,\n) -> Result<()> {\n    if entry.untracked {\n        anyhow::bail!(\"cannot reset hunks for untracked files\");\n    }\n\n    match hunk.section {\n        GitPatchSectionKind::Unstaged => {\n            git_apply_patch(&worktree.path, &[\"-R\"], &hunk.patch, \"reset selected hunk\")\n        }\n        GitPatchSectionKind::Staged => {\n            if entry.unstaged {\n                anyhow::bail!(\n                    \"cannot reset a staged hunk while the file also has unstaged changes; unstage it first\"\n                );\n            }\n            git_apply_patch(\n                &worktree.path,\n                &[\"-R\", \"--index\"],\n                &hunk.patch,\n                \"reset selected staged hunk\",\n            )\n        }\n    }\n}\n\npub fn commit_staged(worktree: &WorktreeInfo, message: &str) -> Result<String> {\n    let message = message.trim();\n    if message.is_empty() {\n        anyhow::bail!(\"commit message cannot be empty\");\n    }","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/worktree/mod.rs#L423-L459","documentation":"reset_hunk on a Staged hunk additionally requires that the file has no unstaged changes (`!entry.unstaged`). The reverse-with-`--index` apply would otherwise desynchronize the index from a working tree that has independent unstaged edits, leaving the repo in a confusing half-reset state. The library refuses rather than risk silent corruption.","triggerScenarios":"Calling reset_hunk on a Staged hunk for a file whose GitStatusEntry reports both `staged == true` and `unstaged == true` (the XY porcelain status has both an index and a worktree change). The file was partially staged and then edited further.","commonSituations":"User staged a hunk, kept editing the same file, then asked to reset the staged hunk; mixed staged/unstaged state for one path that the UI collapses into a single entry.","solutions":["First call unstage_path (or unstage_hunk for the staged hunk) to clear the staged portion, then re-derive the entry and reset.","Inspect `entry.staged` and `entry.unstaged` before reset_hunk and surface a 'unstage first' prompt instead of calling through.","After unstaging, refresh `git_status_entries` so the entry's flags reflect the new state."],"exampleFix":"// before\nreset_hunk(&worktree, &entry, &hunk)?;\n\n// after\nif entry.unstaged && hunk.section == GitPatchSectionKind::Staged {\n    unstage_path(&worktree, &entry.path)?;\n    let fresh = git_status_entries(&worktree)?.into_iter()\n        .find(|e| e.path == entry.path).unwrap();\n    // re-derive hunks, then reset\n} else {\n    reset_hunk(&worktree, &entry, &hunk)?;\n}","handlingStrategy":"validation","validationCode":"use crate::worktree::{GitPatchSectionKind, GitStatusEntry, unstage_path};\n\nfn can_reset_staged_hunk(entry: &GitStatusEntry) -> bool {\n    // Safe only when the file has no parallel unstaged edits.\n    entry.staged && !entry.unstaged\n}\n\nif hunk.section == GitPatchSectionKind::Staged && !can_reset_staged_hunk(&entry) {\n    // must unstage first to avoid index/worktree desync\n    unstage_path(&worktree, &entry.path)?;\n    // refresh entry + hunks, then retry reset on the now-unstaged hunk\n} else {\n    reset_hunk(&worktree, &entry, &hunk)?;\n}","typeGuard":"fn staged_only(entry: &GitStatusEntry) -> bool {\n    entry.staged && !entry.unstaged\n}","tryCatchPattern":"match reset_hunk(&worktree, &entry, &hunk) {\n    Ok(()) => { /* refresh */ }\n    Err(e) if format!(\"{e}\").contains(\"unstaged changes\") => {\n        unstage_path(&worktree, &entry.path)?;\n        // refresh and retry\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Inspect both `entry.staged` and `entry.unstaged` before resetting a staged hunk.","When a file is in a mixed staged/unstaged state, force the user to unstage first.","Refresh `git_status_entries` after every mutating op so flags stay accurate."],"tags":["git","worktree","state-machine","index","validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}