GitoxideLabs/gitoxide · error

cannot split with unresolved conflicts

Error message

cannot split with unresolved conflicts

What it means

Before preparing a commit split, `prepare` loads the worktree changes and refuses to proceed if any path is in the `Unmerged` state. Splitting requires a clean, resolvable set of staged and unstaged hunks; unresolved merge conflicts would make the split ambiguous, so it is aborted up front (before the editor is launched).

Solutions

  1. Resolve the merge conflicts (`gix`/git status shows unmerged paths), then `git add` the resolved files.
  2. Abort the in-progress merge/rebase (`git merge --abort` / `git rebase --abort`) if it should not be continued.
  3. Run `gix tix split` again once `git status` reports no unmerged paths.
  4. Ensure both staged and worktree changes exist afterward, since the same function also requires both groups.

Example fix

// before: splitting during a conflicted merge
repo_split_prepare(&repo)?;
// after: guard on unmerged state first
if has_unmerged_paths(&repo)? {
    anyhow::bail!("resolve conflicts before splitting");
}
repo_split_prepare(&repo)?;
Defensive patterns

Strategy: validation

Validate before calling

fn has_unmerged_paths(repo: &gix::Repository) -> Result<bool> {
    let changes = load_worktree_changes_without_lines(repo)?;
    Ok(changes.paths.iter().any(|c| c.kind == ChangeKind::Unmerged))
}

Try / catch

match prepare(&repo) {
    Ok(p) => p,
    Err(e) if e.to_string().contains("unresolved conflicts") => {
        eprintln!("Resolve merge conflicts (git status) before running split.");
        Err(e)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `prepare` (via `splits_staged_and_worktree_changes_without_touching_files_during_preparation` or `conflicting_staged_and_worktree_hunks_abort_before_the_editor`) when `load_worktree_changes_without_lines` reports at least one change with `kind == ChangeKind::Unmerged` in the repository.

Common situations: A merge or rebase left conflict markers and the user runs `gix tix split` before resolving; a cherry-pick conflict is still open; index contains unmerged entries from a conflicted operation.

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 GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/538b0ad6ea656f10. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/edit/split.rs:24

pub(crate) struct Prepared {
    pub editor: Option<gix::command::Prepare>,
    pub document: Vec<u8>,
    create: create::Prepared,
    target: ObjectId,
    source: gix::objs::Commit,
    tree: ObjectId,
}

#[tracing::instrument(skip_all)]
pub(crate) fn prepare(mut repo: gix::Repository, todo: bool) -> Result<Prepared> {
    let target = repo
        .head_id()
        .context("splitting requires an existing HEAD commit")?
        .detach();
    let changes = load_worktree_changes_without_lines(&repo)?;
    if changes.paths.iter().any(|change| change.kind == ChangeKind::Unmerged) {
        anyhow::bail!("cannot split with unresolved conflicts");
    }
    if !changes.paths.iter().any(|change| change.group == ChangeGroup::Staged)
        || !changes.paths.iter().any(|change| change.group == ChangeGroup::Unstaged)
    {
        anyhow::bail!("splitting requires both staged and worktree changes");
    }

    let mut source = repo
        .find_commit(target)
        .context("could not find HEAD commit")?
        .decode()
        .context("could not decode HEAD commit")?
        .into_owned()
        .context("could not own HEAD commit")?;
    let mut create = create::prepare_from(repo.clone(), Some(target), create::Source::Default, None, todo)?;
    repo.objects.set_object_memory(std::mem::take(&mut create.objects));

    let head_tree = source.tree;

View on GitHub (pinned to e73179060b)