gitbutlerapp/gitbutler · error
Cannot land ` `: it would publish conflicted commit ( )…
Error message
Cannot land `{branch}`: it would publish {} conflicted commit{} ({}). Resolve them first with `but resolve <commit>`. What it means
`validate_branch_landing` refuses to land a branch whose publish set contains conflicted commits. Pushing or merging conflicted commits would produce a broken or rejected integration on the target, so GitButler blocks the land and lists the conflicted commit IDs, directing the developer to resolve them with `but resolve <commit>` first.
Solutions
- Run `but resolve <commit>` for each listed commit and resolve the conflicts, then retry the land.
- Use the GitButler UI/TUI conflict-resolution flow to clear all conflicted commits.
- Remove or rework the conflicted commits if they are no longer needed.
Example fix
// before but land feature-x // refused: would publish 2 conflicted commits (abc123, def456) // after but resolve abc123 but resolve def456 but land feature-x
Defensive patterns
Strategy: validation
Validate before calling
// check for conflicted commits in the publish set before landing
const ws = await api.workspaceState();
const conflicted = ws.stacks.flatMap(s => s.commits).filter(c => c.conflicted);
if (conflicted.length) throw new Error(`Resolve ${conflicted.map(c => c.id).join(', ')} before landing`); Type guard
function hasConflictedCommits(commits) {
return commits.some(c => c.conflicted === true);
} Try / catch
try {
await api.land(branch);
} catch (e) {
const ids = String(e).match(/\(([a-f0-9,\s]+)\)/)?.[1]?.split(',').map(s => s.trim());
if (ids) {
for (const id of ids) await api.resolve(id);
await api.land(branch);
} else throw e;
} Prevention
- Run conflict resolution (`but resolve`) right after any pull/rebase that reports conflicts.
- Check `but status` for conflicted commits before every land.
- Avoid leaving a workspace session with unresolved conflicts pending.
When it happens
Trigger: Calling `branch_land` when `scan.conflicted` is non-empty — one or more commits in the segment(s) that would be published are in a conflicted state (e.g. after a rebase or pull left unresolved conflicts).
Common situations: After `but pull` / `but rebase` introduced conflicts that were not fully resolved; applying upstream changes that conflict with local commits; returning to a workspace after an interrupted conflict-resolution session.
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
- Refusing to land ` `: commit(s) on unnamed segment(s) below…
- Refusing to land ` `: it is stacked on top of other…
- Refusing to land ` ` with --whole-stack: it is not the top…
- Refusing to land ` ` with --whole-stack: it is not the top…
- Aborting due to empty branch name
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/1f992569eb6f50f1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-api/src/land/mod.rs:445
bail!(
"Refusing to land `{branch}`: {} commit(s) on unnamed segment(s) below it would \
also be published to {target_display}. Pass --whole-stack to land `{branch}` \
together with everything below it.",
scan.commits_below,
);
}
bail!(
"Refusing to land `{branch}`: it is stacked on top of {} other segment(s) ({}) \
whose commits would also be published to {target_display}. Land the bottom segment \
`{}`, or pass --whole-stack to land `{branch}` together with everything below it.",
scan.lower_segments.len(),
scan.lower_segments.join(", "),
scan.lower_segments.last().expect("non-empty checked above"),
);
}
if !scan.conflicted.is_empty() {
bail!(
"Cannot land `{branch}`: it would publish {} conflicted commit{} ({}). \
Resolve them first with `but resolve <commit>`.",
scan.conflicted.len(),
if scan.conflicted.len() == 1 { "" } else { "s" },
scan.conflicted.join(", "),
);
}
Ok(scan.lower_segments)
}
/// Fetch the target's fetch remote and record the outcome on the project, mirroring the
/// bookkeeping `fetch_from_remotes` performs so `last_fetched` and auto-fetch scheduling stay
/// accurate for targeted fetches too.
fn fetch_target_remote(ctx: &Context, remote: &str) -> anyhow::Result<()> {
use anyhow::Context as _;
let result = ctx.fetch(remote, Some("land".to_string()));
let timestamp = std::time::SystemTime::now();View on GitHub (pinned to 58e5313667)