GitoxideLabs/gitoxide · error
aborted without changes: refusing to materialize a conflict…
Error message
{operation} aborted without changes: refusing to materialize a conflict without a continuation output file What it means
When conflict materialization is requested with destination '-' (stdout), tix refuses to proceed if stdout is a terminal, because conflict markers piped to an interactive terminal cannot serve as a continuation file. The operation aborts without changes. A real output file is required to continue the rebase later.
Solutions
- Redirect stdout to a file: `tix rebase apply ... --materialize-conflicts - > continuation.out`, or run non-interactively
- Pass a concrete file path instead of '-': `--materialize-conflicts ./rebase-continuation`
- Resolve the conflict upstream so no materialization is needed
Example fix
// before tix rebase apply plan --materialize-conflicts - // after tix rebase apply plan --materialize-conflicts continuation.txt
Defensive patterns
Strategy: validation
Validate before calling
if dest == Path::new("-") && std::io::stdout().is_terminal() {
return Err(anyhow!("use a file path for --materialize-conflicts in interactive shells"));
} Try / catch
if let Err(e) = cmd.status() {
if format!("{e}").contains("refusing to materialize") {
eprintln!("redirect stdout or pass a file path");
}
} Prevention
- Never use '-' for --materialize-conflicts in interactive terminals
- Redirect to a file: `... --materialize-conflicts - > out.txt`
- Prefer explicit paths over '-' for auditability
When it happens
Trigger: Calling `tix rebase apply --materialize-conflicts -` from an interactive shell (stdout is a TTY) while a plan conflict occurs in handle_plan_conflict.
Common situations: Developer runs the command directly in a terminal instead of redirecting output to a file; scripts accidentally inherit a TTY; confusion between '-' (stdout) and a real path.
Understand the failure class
Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.
Related errors
- aborted without changes: conflict while applying ; pass…
- stopped at a materialized conflict
- {notice}
- time-travel would conflict; retry with…
- the conflict index still has unresolved entries
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/493c23acec399086.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/command/rebase.rs:262
}
}
}
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)
.and_then(|_| stdout.flush())
.context("could not write the continuation rebase todo")?;
} else {
let mut output = std::fs::OpenOptions::new()
.write(true)
.create_new(true)View on GitHub (pinned to e73179060b)