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
- Check your step list is non-empty before calling `rebase()` and skip the operation if there is nothing to do
- Debug why step generation produced zero items — usually an over-aggressive filter or an already-up-to-date range
- 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
- Guard step-generation code so it never returns an empty list silently — log when it does
- Treat 'no steps' as a skip at the call site rather than an error when that is a valid state
- Add a builder lint/test that every code path either adds steps or skips rebase()
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
- Invalid selector set: This cannot be empty
- Reference step must have a non-empty virtual branch name
- When using OpenRouter, you must provide a valid API key
- Invalid message format
- HTTP Error ${response.statusText}: ${text}
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/03a80596ba47b8af.
Report an issue: GitHub.