GitoxideLabs/gitoxide · error
rewording the commit would cause a merge conflict
Error message
rewording the commit would cause a merge conflict
What it means
`Perform::complete` unwraps the result of a reword operation: a `Perform::Complete` yields the outcome, but a `Perform::Conflict` means the rebase machinery hit a merge conflict while rewording, which this API does not support interactively. The library converts that into an error stating that rewording would cause a merge conflict.
Solutions
- Abort the reword and resolve conflicts manually with an interactive rebase (`git rebase -i <base>`), editing the message there and resolving conflicts as they appear.
- Reword only the tip commit (no descendants to replay) to avoid the conflict path.
- Use `git commit --amend` after checking out the commit, then rebase descendants with conflict resolution.
Example fix
// before: non-interactive reword that hits conflict let outcome = perform.complete()?; // bails with conflict message // after: shell-based resolution // git rebase -i <base> # mark the commit as `reword`, resolve conflicts as prompted
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check that rewording the tip only (no descendants) avoids replay conflicts
let head = repo.head_id()?.detach();
if commit_id != head {
eprintln!("rewording non-tip commits may conflict; prefer git rebase -i");
} Try / catch
match reword_perform.complete() {
Err(e) if e.to_string().contains("merge conflict") => {
eprintln!("fall back to interactive rebase: git rebase -i <base>, mark the commit as reword");
}
other => other?,
} Prevention
- Reword tip commits non-interactively; use `git rebase -i` for deeper history.
- Avoid interleaved content edits between the reworded commit and its descendants.
- Resolve pending conflicts in the working tree before any reword/rebase operation.
When it happens
Trigger: Calling reword (via `complete`) on a commit whose changes conflict with the surrounding history — typically rewording a commit while `relocate_after_editor` must replay descendants, and those replays clash with the reworded content.
Common situations: Rewording a commit whose message is referenced by patches of later commits is usually fine, but content-level conflicts arise when descendants touch the same lines and the reword path also rewrites content; rebased histories with overlapping edits; interactive edits of deep history.
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
- an edit unexpectedly produced a merge conflict
- could not apply conflict stages to the prepared index
- rebasing would cause a merge conflict
- rebase todo requires at least one -x/--hide revision when…
- the hidden and visible revisions have no editable fork point
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/241adaec65217ab2.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/reword.rs:43
pub(crate) struct Outcome {
pub target: gix::ObjectId,
pub commit: Option<gix::ObjectId>,
pub enrichment: Option<crate::enrich::Enrichment>,
pub ref_rewrites: Vec<rebase::RefRewrite>,
pub ref_changes: Vec<super::undo::RefChange>,
}
pub(crate) enum Perform {
Complete(Outcome),
Conflict(rebase::Conflict),
}
impl Perform {
fn complete(self) -> Result<Outcome> {
match self {
Perform::Complete(outcome) => Ok(outcome),
Perform::Conflict(_) => anyhow::bail!("rewording the commit would cause a merge conflict"),
}
}
}
pub(crate) fn relocate_after_editor(
repo: &gix::Repository,
revisions: &[std::ffi::OsString],
hidden_revisions: &[std::ffi::OsString],
change_id: gix::hash::ChangeId,
) -> Result<(crate::history::HistoryGraph, gix::ObjectId)> {
let graph = super::loaded_view_graph_with_hidden(repo, revisions, hidden_revisions)?;
let mut matches = Vec::new();
for id in graph.stored_commit_ids() {
if crate::change_id::for_commit(repo, id)? == change_id {
matches.push(id);
}
}
match matches.as_slice() {View on GitHub (pinned to e73179060b)