GitoxideLabs/gitoxide · error · anyhow::Error

the conflict index still has unresolved entries

Error message

the conflict index still has unresolved entries

What it means

After staging resolutions with `git add`, the code re-opens the index and verifies every entry is Unconflicted. If any entry still carries a conflict stage (1/2/3), the operation refuses to proceed, because committing with unresolved conflicts would produce a broken state.

Solutions

  1. Run `git status` / `git ls-files -u` to list remaining unmerged entries and resolve them.
  2. Stage every conflicted file (`git add .` or per-path) before retrying the operation.
  3. Check for rename/case mismatches between the resolved file and the index path.
  4. If conflicts come from an in-progress rebase/merge, resolve or abort it first.

Example fix

// before
resolve_and_stage(paths)?;
// after
resolve_and_stage(paths)?;
let left = list_unmerged_entries(repo)?;
if !left.is_empty() {
    anyhow::bail!("unresolved: {:?}", left);
}
Defensive patterns

Strategy: validation

Validate before calling

let unresolved = repo.open_index()?.entries().iter()
    .any(|e| e.stage() != gix::index::entry::Stage::Unconflicted);
if unresolved { /* resolve first */ }

Try / catch

match finalize_resolution(repo) {
    Err(err) if err.to_string() == "the conflict index still has unresolved entries" => {
        eprintln!("resolve remaining conflicts (git ls-files -u) and re-stage");
    }
    other => other?,
}

Prevention

When it happens

Trigger: The conflict resolution flow found that after `git add`, the index still contains staged conflict entries — e.g. resolutions were written to the wrong paths, `git add` staged only some files, or new conflicts appeared.

Common situations: User edited only some conflicted files; a merge/rebase recreated conflicts after staging; path casing or rename mismatches caused some conflicts to remain unstaged.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/a22d0a9fe8169987. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/lib.rs:5655

        .output()
        .context("could not launch git add for resolved paths")?;
    if !output.status.success() {
        let stderr = output.stderr.trim().to_str_lossy();
        if stderr.is_empty() {
            anyhow::bail!("git add for resolved paths failed with {}", output.status);
        }
        anyhow::bail!("git add for resolved paths failed with {}: {stderr}", output.status);
    }

    let index = repository
        .open_index()
        .context("could not verify the resolved conflict index")?;
    if index
        .entries()
        .iter()
        .any(|entry| entry.stage() != gix::index::entry::Stage::Unconflicted)
    {
        anyhow::bail!("the conflict index still has unresolved entries");
    }
    Ok(())
}

fn preview_todo_rebase_conflict(
    app: &mut App,
    conflict: &edit::rebase::PlanConflict,
    authors: &SharedAuthors,
    view_tips: &[gix::ObjectId],
    hidden_tips: &[gix::ObjectId],
) -> Result<()> {
    let repo = conflict.repository();
    let mut rows = Vec::with_capacity(conflict.produced().len());
    let mut attributions = Vec::new();
    for id in conflict.produced().iter().rev().copied() {
        let commit = repo
            .find_commit(id)
            .context("could not load an in-memory rebase result")?;

View on GitHub (pinned to e73179060b)