affaan-m/ECC · error · anyhow::Error

Repository root has uncommitted changes; commit or stash…

Error message

Repository root {} has uncommitted changes; commit or stash them before merging

What it means

merge_into_base also requires the repository root checkout itself to be clean. If `git status --short` in the root is non-empty, the library bails because a merge into the base would mix uncommitted root changes with the incoming merge.

Solutions

  1. Commit the root changes: `git -C <root> add -A && git commit`.
  2. Or stash them: `git -C <root> stash` and retry the merge.
  3. Clean untracked artifacts with `git -C <root> clean -fd` (after reviewing) or gitignore them.
  4. Check `git -C <root> status --short` in your own code before calling merge_into_base.
  5. Redirect root-level work into its own worktree so the base checkout stays clean.

Example fix

// before
merge_into_base(&wt)?; // fails: dirty repo root
// after
let root = base_checkout_path(&wt)?;
Command::new("git").arg("-C").arg(&root).args(["stash"]).status()?;
merge_into_base(&wt)?;
Defensive patterns

Strategy: validation

Validate before calling

let root = base_checkout_path(&wt)?;
if !git_status_short(&root)?.is_empty() {
    eprintln!("root is dirty; commit or stash first");
    return Ok(());
}

Try / catch

if let Err(e) = merge_into_base(&wt) {
    if e.to_string().contains("Repository root") {
        // stash/commit root changes, then retry
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling merge_into_base while the repo root has modified, staged, or untracked files — the same dirty-tree condition as the worktree, but on the base checkout.

Common situations: Hotfix or WIP made directly in the root; build/test artifacts written into the root; pull left local modifications behind.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

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

    if has_uncommitted_changes(worktree)? {
        anyhow::bail!(
            "Worktree {} has uncommitted changes; commit or discard them before merging",
            worktree.branch
        );
    }

    let repo_root = base_checkout_path(worktree)?;
    let current_branch = get_current_branch(&repo_root)?;
    if current_branch != worktree.base_branch {
        anyhow::bail!(
            "Base branch {} is not checked out in repo root (currently {})",
            worktree.base_branch,
            current_branch
        );
    }

    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!(

View on GitHub (pinned to 8321021c54)