gitbutlerapp/gitbutler · error

Cannot currently rebase a commit so that it becomes the…

Error message

Cannot currently rebase a commit so that it becomes the first commit in the history

What it means

During `rebase` execution, a `Pick` step is reached when `cursor` is `None` (no parent position established yet) and the picked commit has at least one parent. The only supported root case is a parentless commit, which is created as a new root; rebasing a non-root commit into the very first commit of history would require dropping its parents, which is intentionally not implemented (see the TODO in the source).

Solutions

  1. Reorder the steps so a parentless (root) commit comes first, or supply a valid `base` so the cursor is initialized.
  2. If the goal is to make a commit root, flatten it by squashing it into the following commit instead of picking it first.
  3. Create the desired history as new commits rather than rebasing an existing parented commit into position zero.

Example fix

// before
steps = [pick(commit_with_parent), pick(root_commit)]; // base=None -> error
// after
steps = [pick(root_commit), pick(commit_with_parent)];
Defensive patterns

Strategy: validation

Validate before calling

fn can_pick_at_front(repo: &gix::Repository, commit_id: gix::ObjectId, base: Option<gix::ObjectId>) -> anyhow::Result<bool> {
    Ok(base.is_none() && repo.find_commit(commit_id)?.parent_ids().next().is_none())
}

Type guard

fn is_root_commit(repo: &gix::Repository, id: gix::ObjectId) -> anyhow::Result<bool> {
    Ok(repo.find_commit(id)?.parent_ids().next().is_none())
}

Try / catch

match rebase(repo, base, base_substitute, steps, pick_mode) {
    Err(e) if e.to_string().contains("first commit in the history") => {
        // reorder steps so a root commit comes first, or set a base
    }
    other => other,
}

Prevention

When it happens

Trigger: Running a rebase where `base` is `None` (no base commit) and a `RebaseStep::Pick` targets a commit with one or more parents, so `cursor` is `None` at that point in the step loop (crates/but-rebase/src/lib.rs:303).

Common situations: Trying to move an ordinary mid-history commit to the front of a stack; constructing an initial-history rewrite from commits that were created with parents; scripted rebases that assume root creation works for any commit.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/547470c815acb3ea. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-rebase/src/lib.rs:305

                            let mut new_commit = commit;
                            if let Some(new_message) = new_message {
                                new_commit.message =
                                    but_core::commit::rewrite_conflict_markers_on_message_change(
                                        new_commit.message.as_ref(),
                                        new_message,
                                    );
                            }
                            cursor = Some(commit::create(
                                repo,
                                new_commit,
                                DateMode::CommitterUpdateAuthorKeep,
                                SignCommit::IfSignCommitsEnabled,
                                None,
                            )?);
                        }
                        None => {
                            // TODO: should this be supported? This would be as easy as forgetting its parents.
                            bail!(
                                "Cannot currently rebase a commit so that it becomes the first commit in the history"
                            )
                        }
                    }
                }
            }
            RebaseStep::SquashIntoPreceding {
                commit_id,
                new_message,
            } => {
                let Some(cursor) = &mut cursor else {
                    bail!("Can't squash if previous commit is missing");
                };
                last_seen_commit = Some(commit_id);
                let base_commit = repo.find_commit(*cursor)?;
                let new_commit = cherry_pick_one(
                    repo,
                    *cursor,

View on GitHub (pinned to 58e5313667)