gitbutlerapp/gitbutler · error
Cannot amend a conflicted commit
Error message
Cannot amend a conflicted commit
What it means
commit_amend refuses when the target commit's tree is conflicted (but_core::Commit::is_conflicted()), because amending a commit that contains conflict markers would bake the unresolved state into history. The check runs on the resolved target commit before any rebase step is built, so nothing is mutated. Resolve the conflicts (or amend a different commit) first.
Source
Thrown at crates/but-workspace/src/commit/commit_amend.rs:66
/// have been written to the shared object database at that point; it is
/// unreachable and gets garbage-collected eventually.
///
/// `context_lines` define how many diff context lines are being used for
/// this particular function call. The provided `context_lines` MUST align
/// with the `context_lines` value used to generate the `DiffSpec`s passed
/// in the `changes` parameter.
pub fn commit_amend<'ws, 'meta, M: RefMetadata>(
mut editor: Editor<'ws, 'meta, M>,
commit: impl ToCommitSelector,
changes: Vec<DiffSpec>,
context_lines: u32,
source: ChangeSource<'_>,
) -> Result<CommitAmendOutcome<'ws, 'meta, M>> {
let (target_selector, target) = editor.find_selectable_commit(commit)?;
let target_id = target.id;
if target.attach(editor.repo()).is_conflicted() {
bail!("Cannot amend a conflicted commit")
}
// An immutable pick would be replaced in the step graph while the rebase copies
// its descendants verbatim and never moves the (immutable) refs pointing at it -
// the amended commit would be written but stay unreachable, with this function
// still reporting success. Fail fast instead.
let Step::Pick(target_pick) = editor.lookup_step(target_selector)? else {
bail!("BUG: Expected pick step from commit selector. This should never happen");
};
if !target_pick.mutable {
bail!(
"cannot amend into {target_id}: the commit is immutable (not part of a mutable branch)"
);
}
// Clone before `create_commit` consumes the vec — needed afterwards
// to determine which changes were consumed (not rejected).
let all_changes = changes.clone();
let create_out = create_commit(View on GitHub (pinned to caf1f223d3)
Solutions
- Resolve the conflicts in that commit (or in the workspace) before amending.
- Undo the conflicted operation and amend its pre-conflict ancestor instead.
- Pre-check with but_core::Commit::is_conflicted() and surface a conflict-resolution prompt instead of an error.
Example fix
// before let outcome = commit_amend(editor, commit_id, changes, 3, source)?; // after use but_core::Commit; let target = editor.find_commit(commit_id)?; ensure!(!target.attach(editor.repo()).is_conflicted(), "resolve conflicts before amending"); let outcome = commit_amend(editor, commit_id, changes, 3, source)?;
Defensive patterns
Strategy: validation
Validate before calling
let (_, target) = editor.find_selectable_commit(commit)?;
if target.attach(editor.repo()).is_conflicted() {
// amend would bake conflict markers into history; resolve first
return prompt_conflict_resolution();
} Type guard
fn amend_target_is_clean(repo: &gix::Repository, id: gix::ObjectId) -> bool {
but_core::Commit::from_id(id.attach(repo))
.map(|c| !c.is_conflicted())
.unwrap_or(false)
} Try / catch
match commit_amend(editor, commit_id, changes, 3, source) {
Err(err) if err.to_string() == "Cannot amend a conflicted commit" => {
ui::error("Resolve conflicts in this commit before amending");
Ok(default_outcome())
}
other => other,
} Prevention
- Disable amend on commits flagged conflicted by but_core::Commit::is_conflicted().
- After a conflicted sync, resolve or undo before edit operations.
- In tests, cover amending conflicted-commit fixtures to assert the guard.
When it happens
Trigger: Calling commit_amend(editor, commit, ...) where the selectable commit found via find_selectable_commit is conflicted — e.g. amending a commit created during a conflicted GitButler integration.
Common situations: Amending a commit produced by GitButler's conflict materialization; syncing an upstream branch with conflicts and then trying to amend the auto-created conflicted commit.
Related errors
- Cannot unapply branch by checking out conflicted commit {new
- Cannot unapply workspace reference by checking out conflicte
- Failed to communicate with LM Studio server: ${error instanc
- Invalid response: ${JSON.stringify(result)}
- When using GitButler's API to summarize code, you must be lo
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/ca947f94b134d69e.
Report an issue: GitHub.