GitoxideLabs/gitoxide · error

aborted without changes: conflict while applying ; pass…

Error message

{operation} aborted without changes: conflict while applying {}; pass --materialize-conflicts to opt in

What it means

The tix rebase command hit a conflict while applying a commit (identified by its 7-char hex OID) but no --materialize-conflicts destination was given. Since rebasing cannot silently rewrite history with unresolved conflicts, the operation aborts with no changes written. The message tells the user exactly which flag enables conflict materialization.

Solutions

  1. Inspect the conflicting commit and rebase onto a base where it applies cleanly, or resolve the conflict manually first
  2. Re-run with --materialize-conflicts <path> (or - for stdout when non-interactive) to write conflict markers and a continuation plan
  3. Check `tix rebase apply` output/undo records to confirm the operation aborted without changes before retrying

Example fix

// before
tix rebase apply <plan>
// after
tix rebase apply <plan> --materialize-conflicts conflicts/
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check: only pass --materialize-conflicts when you have a writable destination
let materialize: Option<&Path> = match cli.materialize_conflicts.as_deref() {
    Some(p) if p != Path::new("-") || !std::io::stdout().is_terminal() => Some(p),
    Some(_) => return Err(anyhow!("--materialize-conflicts - requires non-interactive stdout")),
    None => None,
};

Try / catch

match result {
    Err(e) if e.to_string().contains("conflict while applying") => eprintln!("rebase needs --materialize-conflicts"),
    Err(e) => return Err(e),
    Ok(_) => {}
}

Prevention

When it happens

Trigger: Running `tix rebase apply` (or similar rebase subcommand) whose apply_document hits a plan conflict via handle_plan_conflict while the caller passed no --materialize-conflicts path.

Common situations: Rebasing a branch onto a rewritten base where the patch no longer applies cleanly; forgetting the --materialize-conflicts flag in scripts; automated CI rebases over diverged history.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


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

Appendix: source

Thrown at gix-tix/src/command/rebase.rs:256

            super::print_ref_rewrites(&repo, &outcome.ref_rewrites)?;
            super::record_undo(&repo, "rebase history", Ok(changes));
            Ok(())
        }
        rebase::PlanPerform::Conflict(conflict) => {
            handle_plan_conflict(&repo, conflict, materialize_conflicts, &tips, "rebase")
        }
    }
}

pub(super) fn handle_plan_conflict(
    repo: &gix::Repository,
    mut conflict: rebase::PlanConflict,
    materialize_conflicts: Option<&Path>,
    tips: &[ObjectId],
    operation: &str,
) -> Result<()> {
    let Some(destination) = materialize_conflicts else {
        anyhow::bail!(
            "{operation} aborted without changes: conflict while applying {}; pass --materialize-conflicts to opt in",
            conflict.original().to_hex_with_len(7)
        );
    };
    if destination == Path::new("-") && std::io::stdout().is_terminal() {
        anyhow::bail!(
            "{operation} aborted without changes: refusing to materialize a conflict without a continuation output file"
        );
    }
    conflict.persist_objects()?;
    let plan = conflict.continuation_plan();
    let mapped_tips = tips.iter().filter_map(|id| conflict.map(*id)).collect();
    let continuation = todo::prepare_continuation(conflict.repository(), &plan, mapped_tips, true)?.document;
    let revisions = mapped_revisions(tips, |id| conflict.map(id));
    if destination == Path::new("-") {
        let mut stdout = std::io::stdout().lock();
        stdout
            .write_all(&continuation)

View on GitHub (pinned to e73179060b)