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
- Commit the root changes: `git -C <root> add -A && git commit`.
- Or stash them: `git -C <root> stash` and retry the merge.
- Clean untracked artifacts with `git -C <root> clean -fd` (after reviewing) or gitignore them.
- Check `git -C <root> status --short` in your own code before calling merge_into_base.
- 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
- Do direct work in dedicated worktrees, never the base checkout
- Gitignore build/test artifacts at the repo root
- Run `git status --short` at root as a precheck
- Stash or commit root changes before any merge operation
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
- Base branch is not checked out in repo root (currently )
- cannot reset a staged hunk while the file also has unstaged…
- no staged changes to commit
- selected hunk is already staged
- selected hunk is not staged
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)