gitbutlerapp/gitbutler · error
Cannot unapply branch by checking out conflicted commit {new
Error message
Cannot unapply branch by checking out conflicted commit {new_head_id} What it means
Before checking out a new HEAD during unapply, safe_checkout verifies the target commit is not conflicted (carrying GitButler conflict markers per but_core::Commit::is_conflicted()). Checking out a conflicted commit would materialize conflict markers into the worktree, so the operation is refused. Resolve the conflicts (or pick a different target) before unapplying.
Source
Thrown at crates/but-workspace/src/branch/unapply.rs:730
if selected
.as_ref()
.is_none_or(|(best_generation, _)| generation < *best_generation)
{
selected = Some((generation, ref_to_checkout));
}
}
Ok(selected.map(|(_, ref_to_checkout)| ref_to_checkout))
}
/// Run `safe_checkout`, but provide better error messages if the commit to checkout
/// is conflicted.
fn safe_checkout(
repo: &gix::Repository,
new_head_id: gix::ObjectId,
options: but_core::worktree::checkout::Options,
) -> anyhow::Result<but_core::worktree::checkout::Outcome> {
if but_core::Commit::from_id(new_head_id.attach(repo))?.is_conflicted() {
bail!("Cannot unapply branch by checking out conflicted commit {new_head_id}");
}
but_core::worktree::safe_checkout_from_head(new_head_id, repo, options)
}
/// Check out `ref_to_checkout` using the workspace traversal entrypoint as the
/// current worktree/index source.
///
/// `ws` must be the workspace projection for the currently checked-out `HEAD`.
/// Its graph entrypoint is therefore the commit the index and worktree are
/// expected to match before checkout. This matters when `HEAD` points at a
/// stack segment inside the workspace rather than the workspace tip.
///
/// The helper only updates the index/worktree according to `options`; callers
/// remain responsible for any subsequent `HEAD`, reference, metadata, and
/// projection updates.
fn safe_checkout_ref_to_checkout(
repo: &gix::Repository,
ref_to_checkout: &RefToCheckout,View on GitHub (pinned to caf1f223d3)
Solutions
- Resolve outstanding conflicts in the workspace (or undo the conflicting operation) before unapplying.
- Use GitButler undo to return to a pre-conflict state, then retry the unapply.
- If automating, pre-check target commits with Commit::is_conflicted() and route the user to conflict resolution.
Example fix
// before
let outcome = unapply(repo, meta, &ws, branch, opts)?;
// after
use but_core::Commit;
for (_, seg) in ws.segments_with_commits() {
if Commit::from_id(seg.tip()?.id.attach(repo))?.is_conflicted() {
bail_user!("resolve conflicts before unapplying");
}
}
let outcome = unapply(repo, meta, &ws, branch, opts)?; Defensive patterns
Strategy: validation
Validate before calling
use but_core::Commit;
let target = Commit::from_id(new_head_id.attach(repo))?;
if target.is_conflicted() {
// route the user to conflict resolution instead of unapplying
return prompt_conflict_resolution();
} Type guard
fn commit_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 unapply(repo, meta, &ws, branch, opts) {
Err(err) if err.to_string().contains("conflicted commit") => {
ui::error("Resolve workspace conflicts before unapplying");
Ok(default_outcome())
}
other => other,
} Prevention
- Block unapply actions while the workspace reports unresolved conflicts.
- Pre-check candidate head commits with but_core::Commit::is_conflicted().
- Offer GitButler undo to escape conflicted states.
When it happens
Trigger: Calling unapply paths that invoke safe_checkout with a new_head_id whose commit tree is in a conflicted state — typically a workspace that currently contains unresolved merge conflicts.
Common situations: Unapplying branches while the workspace still shows unresolved conflicts from an integration/sync; commits created by GitButler's conflict materialization left in place; retrying an unapply right after a conflicted upstream merge.
Related errors
- Cannot unapply workspace reference by checking out conflicte
- Refusing to work on workspace whose workspace commit isn't a
- Cannot unapply branch '{branch}' from an ad-hoc workspace be
- Cannot unapply non-existing branch '{branch}'
- Cannot unapply a branch from an ad-hoc detached workspace
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/c4c67232b65ae4e2.
Report an issue: GitHub.