affaan-m/ECC · error
git merge failed: {stderr}
Error message
git merge failed: {stderr} What it means
Thrown by merge_into_base at ecc2/src/worktree/mod.rs:897 when `git -C <repo_root> merge --no-edit <worktree.branch>` exits non-zero. By this point all pre-flight checks (merge readiness, clean worktree, correct base branch, clean repo root) have passed, so the failure is from git itself — typically a content conflict that the dry-run readiness check did not predict, a ref mismatch, or a hook rejection. The bail forwards git's stderr verbatim.
Source
Thrown at ecc2/src/worktree/mod.rs:897
}
if !git_status_short(&repo_root)?.is_empty() {
anyhow::bail!(
"Repository root {} has uncommitted changes; commit or stash them before merging",
repo_root.display()
);
}
let output = Command::new("git")
.arg("-C")
.arg(&repo_root)
.args(["merge", "--no-edit", &worktree.branch])
.output()
.context("Failed to merge worktree branch into base")?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("git merge failed: {stderr}");
}
let merged_output = format!(
"{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
Ok(MergeOutcome {
branch: worktree.branch.clone(),
base_branch: worktree.base_branch.clone(),
already_up_to_date: merged_output.contains("Already up to date."),
})
}
pub fn rebase_onto_base(worktree: &WorktreeInfo) -> Result<RebaseOutcome> {
if has_uncommitted_changes(worktree)? {
anyhow::bail!(View on GitHub (pinned to 01e15490f0)
Solutions
- Inspect the forwarded stderr for the exact conflict path; run `git -C <repo_root> status` to see conflicted files and resolve them, then `git merge --continue` (or `--abort` to roll back).
- If a hook rejected the merge, fix the hook's complaint (format the code, remove the secret) or run the merge with `--no-verify` manually if your policy allows it.
- Re-run merge_readiness on the worktree right before merge_into_base to catch conflicts that emerged between scheduling and execution.
- If the worktree branch was force-pushed, re-sync: rebase the worktree onto the new tip before merging.
Example fix
// before
let outcome = merge_into_base(&worktree)?;
// after: surface git's conflict detail and abort cleanly
match merge_into_base(&worktree) {
Ok(o) => Ok(o),
Err(e) if e.to_string().contains("git merge failed") => {
let _ = Command::new("git").arg("-C").arg(&repo_root)
.args(["merge", "--abort"]).status();
anyhow::bail!("merge of {} aborted; resolve conflicts: {e}", worktree.branch);
}
Err(e) => Err(e),
} Defensive patterns
Strategy: try-catch
Validate before calling
// Re-run readiness immediately before merge to catch late conflicts
let readiness = merge_readiness(&worktree)?;
if readiness.status == MergeReadinessStatus::Conflicted {
anyhow::bail!("pre-merge conflict: {}", readiness.summary);
}
let repo_root = base_checkout_path(&worktree)?;
if get_current_branch(&repo_root)? != worktree.base_branch
|| !git_status_short(&repo_root)?.is_empty() {
anyhow::bail!("repo root not ready for merge");
} Type guard
null
Try / catch
match merge_into_base(&worktree) {
Ok(o) => Ok(o),
Err(e) if e.to_string().starts_with("git merge failed") => {
let repo_root = base_checkout_path(&worktree)?;
let _ = Command::new("git").arg("-C").arg(&repo_root)
.args(["merge", "--abort"]).status();
// fall back: rebase the worktree onto base to linearize, then merge
let _ = rebase_onto_base(&worktree);
Err(e)
}
Err(e) => Err(e),
} Prevention
- Run merge_readiness within milliseconds of merge_into_base, not minutes.
- Disable or relax pre-merge hooks that reject agent-generated commits unless policy mandates them.
- Pin the worktree branch tip (record its OID) before merge and verify it is unchanged at merge time.
- Keep branches short-lived so the conflict surface stays small.
When it happens
Trigger: Conflicts on files modified in both branches since the merge base; pre-merge or prepare-commit-msg hooks that exit non-zero; the worktree branch was deleted or force-pushed between the readiness check and the merge command; large-file issues (LFS smudge failures); author/identity config problems when committer hooks fire.
Common situations: Two worktree sessions edited the same files and the second merge conflicts; force-push to the worktree branch changed its tip after merge_readiness ran; a pre-commit hook (lint, format, secret-scan) rejected the merge commit; git LFS not installed or authenticated and a tracked binary file fails to fetch.
Related errors
- Merge blocked between {left_branch} and {right_branch} by {}
- git rebase failed: {}{}
- git apply failed while trying to {action}: {stderr}
- git commit failed: {stderr}
- git merge-tree failed: {stderr}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/72ce8a35c0c5fa82.
Report an issue: GitHub.