gitbutlerapp/gitbutler · error
commits cannot be moved to the merge base
Error message
commits cannot be moved to the merge base
What it means
In the status TUI's move mode (crates/but/src/command/legacy/status/tui/app/move_mode.rs:393), the selected target is converted to a move::MoveTarget; the merge-base lane (MoveTarget::MergeBase) is deliberately rejected because commits can only be moved onto a branch tip, a commit (with an insert side), or a linked-worktree tip — never onto the merge base itself.
Source
Thrown at crates/but/src/command/legacy/status/tui/app/move_mode.rs:393
Ok(())
}
}
fn move_target(
target: MoveTarget<'_>,
insert_side: InsertSide,
) -> anyhow::Result<r#move::MoveTarget> {
Ok(match target {
MoveTarget::Branch { name } => r#move::MoveTarget::BranchTip {
name: Category::LocalBranch.to_full_name(name)?,
},
MoveTarget::Commit(commit) => r#move::MoveTarget::Commit {
commit,
side: targeting::Side::from(insert_side),
},
MoveTarget::WorktreeTip(name) => r#move::MoveTarget::BranchTip { name },
MoveTarget::MergeBase => anyhow::bail!("commits cannot be moved to the merge base"),
})
}
fn move_with(
ctx: &mut Context,
move_op: MoveOperation,
) -> anyhow::Result<Option<SelectAfterReload>> {
let mut guard = ctx.exclusive_worktree_access();
let mut meta = ctx.meta()?;
let (outcome, _ws) = r#move::run(ctx, &mut meta, guard.write_permission(), move_op)?;
Ok(match outcome {
MoveOperationOutcome::Commits { moved_commits, .. } => {
Some(SelectAfterReload::Commit(moved_commits.head.commit_id))
}
MoveOperationOutcome::Changes { new_commit, .. } => {
Some(SelectAfterReload::Commit(new_commit.commit_id))
}View on GitHub (pinned to caf1f223d3)
Solutions
- Choose a concrete commit or branch tip as the move target.
- To move a commit to the bottom of a stack, target the first commit of that stack instead.
- Fix the selection UI so the merge-base lane is non-selectable in move mode, preventing the error entirely.
Example fix
// before let target = MoveTarget::MergeBase; // then converted -> bails // after let target = MoveTarget::Commit(first_commit_of_stack);
Defensive patterns
Strategy: validation
Validate before calling
if matches!(target, MoveTarget::MergeBase) {
// exclude merge-base lanes from selectable move targets in the UI
return Ok(());
} Type guard
fn is_valid_move_target(target: &MoveTarget<'_>) -> bool {
!matches!(target, MoveTarget::MergeBase)
} Try / catch
if let Err(err) = move_with(&mut ctx, move_op) {
if err.to_string().contains("merge base") {
// re-enter move mode and prompt for a commit/branch-tip target
} else { return Err(err); }
} Prevention
- Filter merge-base rows out of move-target selection in the TUI.
- Route 'move to bottom of stack' intents to the first commit of the stack.
- Unit-test the MoveTarget conversion for every variant.
When it happens
Trigger: Entering move mode and accepting the merge-base/merge-commit row as the destination; a keybinding or selection handler that allows the merge-base heading to be picked as a move target.
Common situations: Users trying to move a commit to the very bottom of a stack; new key handlers or fuzzy selectors that do not filter out the merge-base lane.
Related errors
- Commit {} was marked as not conflictable, but resulted in a
- cannot mix mark sources
- cannot mark files from multiple commits
- When using OpenRouter, you must provide a valid API key
- Login token expired. Please log in to GitButler again.
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/c18c3524425295ca.
Report an issue: GitHub.