affaan-m/ECC · warning · anyhow::Error
no staged changes to commit
Error message
no staged changes to commit
What it means
commit_staged calls has_staged_changes (which scans `git_status_entries` for any entry with `staged == true`) and bails if none exist. This prevents `git commit` from failing or producing an empty commit. It is a state precondition, not a git subprocess failure.
Source
Thrown at ecc2/src/worktree/mod.rs:461
);
}
git_apply_patch(
&worktree.path,
&["-R", "--index"],
&hunk.patch,
"reset selected staged hunk",
)
}
}
}
pub fn commit_staged(worktree: &WorktreeInfo, message: &str) -> Result<String> {
let message = message.trim();
if message.is_empty() {
anyhow::bail!("commit message cannot be empty");
}
if !has_staged_changes(worktree)? {
anyhow::bail!("no staged changes to commit");
}
let output = Command::new("git")
.arg("-C")
.arg(&worktree.path)
.args(["commit", "-m", message])
.output()
.context("Failed to create commit")?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("git commit failed: {stderr}");
}
let rev_parse = Command::new("git")
.arg("-C")
.arg(&worktree.path)
.args(["rev-parse", "--short", "HEAD"])
.output()View on GitHub (pinned to 01e15490f0)
Solutions
- Call `git_status_entries` immediately before commit and disable the commit affordance unless at least one entry has `staged == true`.
- Stage explicitly via stage_path/stage_hunk before retrying.
- Refresh status after any staging mutation and re-check before commit.
Example fix
// before
let hash = commit_staged(&worktree, msg)?;
// after
if !has_staged_changes(&worktree)? {
return Err(anyhow!("nothing staged; stage changes first"));
}
let hash = commit_staged(&worktree, msg)?; Defensive patterns
Strategy: validation
Validate before calling
use crate::worktree::has_staged_changes;
if !has_staged_changes(&worktree)? {
return Err(anyhow!("nothing staged to commit; stage at least one path first"));
}
let hash = commit_staged(&worktree, msg)?; Type guard
fn has_any_staged(entries: &[GitStatusEntry]) -> bool {
entries.iter().any(|e| e.staged)
} Try / catch
match commit_staged(&worktree, msg) {
Ok(hash) => Ok(hash),
Err(e) if format!("{e}").contains("no staged changes") => {
// surface 'stage changes first' and abort
Err(e)
}
Err(e) => Err(e),
} Prevention
- Refresh `git_status_entries` right before enabling the commit button and gate it on `entry.staged`.
- After every commit, refresh status so the button does not stay enabled on stale state.
- Avoid concurrent commit paths in the same worktree.
When it happens
Trigger: User hits commit after unstaging everything; staged changes were already committed by another path; status was stale (the index changed underneath the UI) so the caller believed something was staged when nothing was.
Common situations: Double-commit attempt (UI did not refresh after the previous commit); race where a background task reset the index; user unstaged the last path but the commit button stayed enabled.
Related errors
- cannot reset a staged hunk while the file also has unstaged
- commit message cannot be empty
- git add failed for {path}: {stderr}
- git reset failed for {path}: {stderr}
- git restore failed for {}: {stderr}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/48b3b4530ab2940f.
Report an issue: GitHub.