affaan-m/ECC · error

git commit failed

Error message

git commit failed: {stderr}

What it means

Thrown when the `git commit -m <message>` subprocess exits non-zero. The library includes git's stderr verbatim so the underlying cause — identity not configured, hooks failing, GPG signing errors, lock contention — is visible. The commit itself did not happen.

Solutions

  1. Read the stderr embedded in the message; it names the exact git failure.
  2. Configure identity if stderr says 'Please tell me who you are': set user.name and user.email.
  3. If a hook failed, fix the hook violation or bypass temporarily with --no-verify (adjust the command or skip hooks in this wrapper).
  4. For gpg.signing errors, ensure the GPG key exists/unlocked, or disable commit.gpgsign.
  5. Remove a stale .git/index.lock only after confirming no other git process is running.

Example fix

// before: commit with no identity configured
commit_staged(&worktree, msg)?;

// after: ensure identity exists first
Command::new("git").args(["config", "user.name"]).status()?;
Command::new("git").args(["config", "user.email"]).status()?;
commit_staged(&worktree, msg)?;
Defensive patterns

Strategy: try-catch

Validate before calling

fn git_identity_configured(worktree: &WorktreeInfo) -> bool {
    Command::new("git").arg("-C").arg(&worktree.path)
        .args(["config", "user.email"])
        .output().map(|o| o.status.success()).unwrap_or(false)
}

Type guard

None

Try / catch

match commit_staged(&worktree, &msg) {
    Ok(hash) => println!("committed {hash}"),
    Err(e) => {
        let stderr = e.to_string();
        if stderr.contains("who you are") { configure_identity_hint(); }
        else if stderr.contains("hook") { show_hook_failure(&stderr); }
        else { return Err(e); }
    }
}

Prevention

When it happens

Trigger: Calling commit_staged when git exits with failure: missing user.name/user.email, a pre-commit hook rejects the change, commit.gpgsign fails to sign, .git/index.lock is held, or the message triggers template issues.

Common situations: Fresh machine without git identity configured; company repos with mandatory commit-msg hooks; GPG keys absent or expired in signing setups; concurrent tooling (IDE + CLI) leaving index.lock behind.

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


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/b3c9284056473398. Report an issue: GitHub.

Appendix: source

Thrown at ecc2/src/worktree/mod.rs:472

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()
        .context("Failed to resolve commit hash")?;
    if !rev_parse.status.success() {
        let stderr = String::from_utf8_lossy(&rev_parse.stderr);
        anyhow::bail!("git rev-parse failed: {stderr}");
    }

    Ok(String::from_utf8_lossy(&rev_parse.stdout)
        .trim()
        .to_string())
}

View on GitHub (pinned to 8321021c54)