{"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":null,"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/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/worktree/mod.rs#L423-L459","documentation":"reset_hunk refuses to reverse-apply a staged hunk (`git apply -R --index`) when the same file still has unstaged changes. Doing so would corrupt the working tree state because git's index-level reverse apply requires the working tree to match the index for that file. The library enforces the ordering: unstage or discard unstaged hunks first.","triggerScenarios":"Calling reset_hunk with a hunk whose section is Staged while entry.unstaged == true — i.e. the file appears in both the staged and unstaged sections of the status view.","commonSituations":"Editing a file after partially staging it (via stage_hunk or `git add -p`), then trying to reset the staged portion directly; UIs that do not disable staged-hunk reset actions when the file has additional unstaged edits.","solutions":["Unstage the file first (unstage_path or unstage_hunk), then reset the desired hunks.","Discard the unstaged hunks of that file first (reset_hunk on its Unstaged hunks), then reset the staged hunk.","In UI code, guard: only enable staged-hunk reset when entry.unstaged is false."],"exampleFix":"// before: direct reset of staged hunk\nreset_hunk(&worktree, &entry, &staged_hunk)?;\n\n// after: unstage first when mixed state\nif entry.unstaged {\n    unstage_path(&worktree, &entry)?;\n}\nreset_hunk(&worktree, &entry, &staged_hunk)?;","handlingStrategy":"validation","validationCode":"fn can_reset_staged_hunk(entry: &GitStatusEntry) -> bool {\n    !entry.unstaged\n}","typeGuard":"fn staged_hunk_reset_ok(entry: &GitStatusEntry, hunk: &GitPatchHunk) -> bool {\n    matches!(hunk.section, GitPatchSectionKind::Staged) && !entry.unstaged\n}","tryCatchPattern":"match reset_hunk(&worktree, &entry, &hunk) {\n    Err(e) if e.to_string().contains(\"unstaged changes\") => {\n        unstage_path(&worktree, &entry)?;\n        reset_hunk(&worktree, &entry, &hunk)?;\n    }\n    other => other?,\n}","preventionTips":["Before resetting a staged hunk, check whether the file also has unstaged hunks.","Enforce order in UI flows: resolve unstaged hunks first, then staged ones.","Disable staged-hunk reset buttons when the status entry shows mixed staged/unstaged state."],"tags":["git","precondition","staging-conflict"],"backgroundTag":"invalid-state-transition","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}