affaan-m/ECC · error

Base branch {} is not checked out in repo root (currently {}

Error message

Base branch {} is not checked out in repo root (currently {})

What it means

Thrown by merge_into_base at ecc2/src/worktree/mod.rs:874 when the repository root (the primary checkout that owns the worktree) is not currently sitting on the configured base branch. The merge step shells out `git merge` with -C pointed at base_checkout_path(), so git would otherwise merge into whatever branch happens to be checked out. The guard compares get_current_branch(repo_root) against worktree.base_branch (from the WorktreeInfo captured at session creation) and refuses to proceed on mismatch.

Source

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

}

pub fn merge_into_base(worktree: &WorktreeInfo) -> Result<MergeOutcome> {
    let readiness = merge_readiness(worktree)?;
    if readiness.status == MergeReadinessStatus::Conflicted {
        anyhow::bail!(readiness.summary);
    }

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

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Run `git -C <repo_root> checkout <base_branch>` (the value of worktree.base_branch) so the repo root matches what the session recorded, then retry merge_into_base.
  2. If you intentionally want to merge into the currently checked-out branch instead, update the WorktreeInfo.base_branch field (or recreate the session) so it matches reality before calling merge.
  3. If the repo root is in detached HEAD, checkout the named base branch explicitly to attach HEAD to a ref.
  4. Avoid running concurrent operations that mutate the repo root's HEAD while a merge is in flight.

Example fix

// before: merge assumes repo root is on base_branch
merge_into_base(&worktree)?;

// after: ensure repo root is on base_branch first
let repo_root = std::env::current_dir()?;
let current = get_current_branch(&repo_root)?;
if current != worktree.base_branch {
    Command::new("git")
        .arg("-C").arg(&repo_root)
        .args(["checkout", &worktree.base_branch])
        .status()?;
}
merge_into_base(&worktree)?;
Defensive patterns

Strategy: validation

Validate before calling

fn repo_root_on_base(worktree: &WorktreeInfo) -> Result<bool> {
    let repo_root = base_checkout_path(worktree)?;
    let current = get_current_branch(&repo_root)?;
    Ok(current == worktree.base_branch)
}

// before merge_into_base:
if !repo_root_on_base(&worktree)? {
    Command::new("git").arg("-C").arg(&base_checkout_path(&worktree)?)
        .args(["checkout", &worktree.base_branch]).status()?;
}

Type guard

null

Try / catch

match merge_into_base(&worktree) {
    Ok(o) => o,
    Err(e) => {
        let msg = e.to_string();
        if msg.contains("is not checked out in repo root") {
            // surface the current vs expected branch to the user, offer checkout
            return Err(e);
        }
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Calling merge_into_base(&WorktreeInfo) after a developer manually `git checkout`'d a different branch in the main repo, or after another session left the repo root on its own feature branch. Also fires when the base branch recorded in WorktreeInfo has since been renamed or when the repo root is in detached-HEAD state (rev-parse --abbrev-ref HEAD returns 'HEAD').

Common situations: Concurrent agent sessions sharing one repo root where one session switched the root's branch; CI runs that checkout PR branches before invoking the merge; local development where the user switched branches in their editor while an ECC session is mid-merge; base_branch recorded as 'main' but repo default was renamed to 'master' or vice versa.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/a4da82dc5c21c93e. Report an issue: GitHub.