affaan-m/ECC · error · anyhow::Error
git diff failed
Error message
git diff failed: {stderr} What it means
`git_diff_patch_text_for_paths` runs a filtered `git diff` and bails when the command exits non-zero, forwarding git's stderr. This is a wrapper over git plumbing, so the error means git itself rejected the diff invocation (bad rev, bad pathspec, corrupt index) — the message mirrors whatever git printed.
Solutions
- Read the stderr in the message for git's specific complaint (e.g. 'fatal: ambiguous argument')
- For unborn-branch repos, guard the call: only diff once HEAD exists ('git rev-parse HEAD' succeeds)
- Remove a stale lock: check for .git/index.lock and delete it if no git process is running
- Verify the paths passed as filters exist and are tracked, or pass '--' before pathspecs
- Run 'git diff <same-args>' manually in the worktree to reproduce
Example fix
// before: fails on unborn HEAD
git_status_patch_view(&wt)?;
// after: skip diff when HEAD missing
let has_head = Command::new("git")
.args(["rev-parse", "--verify", "HEAD"])
.current_dir(&wt.path)
.output()?;
let view = if has_head.status.success() {
git_status_patch_view(&wt)?
} else {
PatchView::default()
}; Defensive patterns
Strategy: try-catch
Validate before calling
let has_head = Command::new("git")
.args(["rev-parse", "--verify", "HEAD"])
.current_dir(&wt.path)
.output()
.map(|o| o.status.success())
.unwrap_or(false); Try / catch
match git_status_patch_view(&wt) {
Ok(v) => v,
Err(e) if e.to_string().contains("ambiguous argument") => {
// unborn HEAD (no commits yet) — treat as empty view
PatchView::default()
}
Err(e) => return Err(e),
} Prevention
- Only diff after the repo has at least one commit
- Pass '--' before pathspecs to disambiguate paths from refs
- Clear stale .git/index.lock files after crashed processes
- Reproduce failing git diff args manually before filing issues
When it happens
Trigger: Calling git_status_patch_view (which calls this function) when the repo has no HEAD yet (unborn branch), a pathspec matches nothing with certain flags, the index is corrupt/locked, or invalid refs are passed as path filters.
Common situations: Freshly `git init`ed repo with no commits; a race where the worktree's branch was deleted; an index.lock left by a crashed process; quoting issues in path arguments.
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 worktree list --porcelain failed
- Base branch is not checked out in repo root (currently )
- branch name is not a valid git ref
- cannot reset a staged hunk while the file also has unstaged…
- cannot reset hunks for untracked files
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/bc3ca3c1c9ce646a.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/worktree/mod.rs:1079
let mut command = Command::new("git");
command
.arg("-C")
.arg(worktree_path)
.arg("diff")
.args(["--patch", "--find-renames"]);
command.args(extra_args);
command.arg("--");
for path in paths {
command.arg(path);
}
let output = command
.output()
.context("Failed to generate filtered git patch")?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("git diff failed: {stderr}");
}
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
}
fn git_diff_patch_lines_for_paths(
worktree_path: &Path,
extra_args: &[&str],
paths: &[String],
) -> Result<Vec<String>> {
if paths.is_empty() {
return Ok(Vec::new());
}
let mut command = Command::new("git");
command
.arg("-C")
.arg(worktree_path)View on GitHub (pinned to 8321021c54)