affaan-m/ECC · error · anyhow::Error
git merge failed
Error message
git merge failed: {stderr} What it means
This error is raised by `merge_into_base` when a `git merge --no-edit <branch>` command executed in the base checkout exits with a non-zero status. The library surfaces git's raw stderr so the developer can see the actual merge conflict or failure. It wraps all git-level merge failures, including conflicts, unrelated histories, and corrupt refs.
Solutions
- Inspect the stderr in the message, run 'git merge --no-edit <branch>' manually in the base checkout to see conflict markers
- Resolve conflicts: run 'git status', edit conflicted files, 'git add' them, 'git commit' to complete the merge
- If conflicts are hard to reconcile, rebase the worktree branch onto the base first ('git rebase <base>') then retry
- If histories are unrelated, merge with '--allow-unrelated-histories' or rebuild the branch from the correct base
- Ensure the base checkout is clean and on the expected base branch before retrying
Example fix
// before (raw merge that fails)
let output = Command::new("git").args(["merge", "--no-edit", &worktree.branch]).output()?;
// after (pre-check the merge and abort cleanly on conflict)
let check = Command::new("git").args(["merge-tree", "--write-tree", &worktree.branch]).output()?;
anyhow::ensure!(check.status.success(), "merge conflicts detected; resolve before merging"); Defensive patterns
Strategy: try-catch
Validate before calling
let check = Command::new("git")
.args(["merge-tree", "--write-tree", &worktree.branch])
.current_dir(&repo_root)
.output()?;
let merge_clean = check.status.success(); Type guard
fn is_merge_conflict(err: &anyhow::Error) -> bool {
err.to_string().contains("CONFLICT")
} Try / catch
match merge_into_base(&wt) {
Ok(outcome) => outcome,
Err(e) if e.to_string().contains("CONFLICT") => {
eprintln!("Resolve merge conflicts in {} then retry", wt.branch);
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Keep feature branches short-lived and merge back to base frequently
- Rebase onto base regularly to surface conflicts early
- Ensure the base checkout is clean and on the correct branch before merging
- Dry-run with 'git merge-tree' or 'git merge --no-commit --no-ff' in scripts
When it happens
Trigger: Calling merge_into_base when the worktree branch and base branch have diverged and git cannot auto-merge (conflict markers required), when the merge is refused (e.g. 'refusing to merge unrelated histories'), or when the underlying git process fails for any reason.
Common situations: Parallel development where base branch advanced with conflicting edits; a worktree branch that was rebased onto a different root; a branch deleted or corrupted underneath the tool; divergent commits touching the same lines in the base checkout.
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 merge-tree failed
- readiness.summary
- git rebase failed
- Base branch is not checked out in repo root (currently )
- branch name is not a valid git ref
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/72ce8a35c0c5fa82.
Report an issue: GitHub.
Appendix: 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 8321021c54)