gitbutlerapp/gitbutler · error

No rebase steps provided

Error message

No rebase steps provided

What it means

`Rebase::rebase()` executes the step list accumulated via `Rebase::steps()` and refuses to run when that list is empty — a rebase with nothing to pick, merge, fixup, or reference is treated as a programming error rather than a no-op. The builder validates each step as it is added, but the empty-list check happens at execution time.

Source

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

        self
    }

    /// Performs a rebase on top of a given base, according to the provided steps, or fails if no step was provided.
    /// It does not actually create new git references nor does it update existing ones, it only deals with
    /// altering commits and providing the information needed to update refs.
    ///
    /// Use it to
    ///
    ///  - drop commits
    ///  - insert new commits
    ///  - reorder commits
    ///  - rewrite the history at will
    ///
    /// **However, note that it will also make all input commits sequential, so the caller must assure
    /// these actually form a 'line'.**
    pub fn rebase(&mut self) -> Result<RebaseOutput> {
        if self.steps.is_empty() {
            return Err(anyhow!("No rebase steps provided"));
        }
        let pick_mode = if self.rebase_noops {
            PickMode::Unconditionally
        } else {
            PickMode::SkipIfNoop
        };
        rebase(
            self.repo,
            self.base,
            self.base_substitute,
            std::mem::take(&mut self.steps),
            pick_mode,
        )
    }
}

impl Rebase<'_> {
    /// Pick, Merge and Fixup operations:

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Check your step list is non-empty before calling `rebase()` and skip the operation if there is nothing to do
  2. Debug why step generation produced zero items — usually an over-aggressive filter or an already-up-to-date range
  3. Return early with `Ok(default)` semantics at the call site when 'nothing to rebase' is a valid outcome

Example fix

// before
let out = rebase.rebase()?; // Err: No rebase steps provided

// after
let out = if steps.is_empty() {
    return Ok(RebaseOutput::default()); // or skip the rebase entirely
} else {
    rebase.steps(steps)?.rebase()?
};
Defensive patterns

Strategy: validation

Validate before calling

if steps.is_empty() {
    return Ok(RebaseOutput::default()); // nothing to rebase is a valid outcome here
}
rebase.steps(steps)?.rebase()?;

Prevention

When it happens

Trigger: Constructing `Rebase::new(repo, base, substitute)` and calling `.rebase()` without ever calling `.steps(...)`; or passing an empty iterator to `.steps([])` which adds (and validates) nothing.

Common situations: Dynamic step generation that filters out every commit (e.g. empty diff range, no commits between base and target); early-return logic that skips adding steps but still calls rebase; tests that build the builder mechanically.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/03a80596ba47b8af. Report an issue: GitHub.