affaan-m/ECC · error
git restore failed for
Error message
git restore failed for {}: {stderr} What it means
Thrown by reset_path when `git restore` used to discard unstaged changes for a status entry exits non-zero. The function wraps the git CLI and forwards its stderr in the message. It signals that discarding the file's working-tree changes failed at the git level.
Solutions
- Inspect the stderr in the message for git's specific failure reason.
- Skip reset_path for untracked entries (entry.untracked == true); delete the file or use remove_path semantics instead.
- Confirm the file still exists and is tracked: `git ls-files --error-unmatch <path>` before restoring.
- Check sparse-checkout configuration if stderr mentions excluded paths.
Example fix
// before: reset regardless of state
reset_path(&worktree, &entry)?;
// after: only reset tracked files
if !entry.untracked {
reset_path(&worktree, &entry)?;
} Defensive patterns
Strategy: validation
Validate before calling
fn can_reset(worktree: &WorktreeInfo, entry: &GitStatusEntry) -> bool {
!entry.untracked
&& worktree.path.join(&entry.path).exists()
&& worktree.path.join(".git").exists()
} Type guard
fn is_tracked_modified(entry: &GitStatusEntry) -> bool { !entry.untracked && entry.unstaged } Try / catch
match reset_path(&worktree, &entry) {
Ok(()) => refresh_status(),
Err(e) => show_dialog("Discard failed", &format!("{e:#}")),
} Prevention
- Guard on entry.untracked: untracked files must be deleted, not restored.
- Confirm the path still exists on disk before discarding.
- Refresh status entries right before destructive operations to avoid stale data.
When it happens
Trigger: Calling reset_path(worktree, entry) when `git restore -- <path>` fails: file is untracked (restore only works on tracked files), path no longer exists, checkout conflicts with sparse-checkout settings, or the repo lacks a HEAD.
Common situations: Discarding changes on an untracked file (should be deleted instead of restored); file deleted from disk but still in the index; running inside a shallow or empty clone where HEAD is unborn; sparse-checkout entries excluded from the cone.
Understand the failure class
Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.
Related errors
- git reset failed for
- Base branch is not checked out in repo root (currently )
- git commit failed
- git log failed
- git rev-parse failed
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/a6091ab4ebc802f8.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/worktree/mod.rs:353
} else {
fs::remove_file(&target)
.with_context(|| format!("Failed to remove {}", target.display()))?;
}
return Ok(());
}
let output = Command::new("git")
.arg("-C")
.arg(&worktree.path)
.args(["restore", "--source=HEAD", "--staged", "--worktree", "--"])
.arg(&entry.path)
.output()
.with_context(|| format!("Failed to reset {}", entry.path))?;
if output.status.success() {
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("git restore failed for {}: {stderr}", entry.path);
}
}
pub fn git_status_patch_view(
worktree: &WorktreeInfo,
entry: &GitStatusEntry,
) -> Result<Option<GitStatusPatchView>> {
if entry.untracked {
return Ok(None);
}
let staged_patch =
git_diff_patch_text_for_paths(&worktree.path, &["--cached"], &[entry.path.clone()])?;
let unstaged_patch = git_diff_patch_text_for_paths(&worktree.path, &[], &[entry.path.clone()])?;
let mut sections = Vec::new();
let mut hunks = Vec::new();
View on GitHub (pinned to 8321021c54)