GitoxideLabs/gitoxide · error
the parent of a repeated rebase must not be pending
Error message
the parent of a repeated rebase must not be pending
What it means
During rebase edit validation, when `repeat` is set, the parent of the first affected commit (`affected.first()`) must NOT itself be pending. If the parent commit is part of an unfinished rebase, rebasing a descendant on top of it would corrupt the in-progress rebase ordering, so the edit bails with this message.
Solutions
- Rebase the pending parent commit first (or complete it) before repeating a rebase whose base hangs under it.
- Choose a base whose parent is not pending — start the repeated range higher or lower in the history.
- Reorder the edit operations so the rebase proceeds root-to-tip and never attaches to a pending parent.
- Abort the pending rebase involving the parent, then retry the edit.
Example fix
// before: base parent is still pending let parent = graph.parents_of(base).unwrap()[0]; assert!(!is_pending(&repo.find_commit(parent)?.decode()?)); // fails edit.rebase(base, true, ...)?; // after: resolve the pending parent first finish_or_abort_pending(parent)?; let parent = graph.parents_of(base).unwrap()[0]; edit.rebase(base, true, ...)?;
Defensive patterns
Strategy: validation
Validate before calling
let base = *affected.first().context("empty range")?;
if let Some(parent) = graph.parents_of(base).and_then(|p| p.first().copied()) {
let c = repo.find_commit(parent)?.decode()?.into_owned()?;
debug_assert!(!gix_tix::edit::rebase::is_pending(&c));
}
Type guard
fn parent_is_settled(repo: &gix::Repository, graph: &Graph, base: ObjectId) -> anyhow::Result<bool> {
Ok(graph.parents_of(base)
.and_then(|p| p.first().copied())
.map(|parent| !gix_tix::edit::rebase::is_pending(&repo.find_commit(parent)?.decode()?.into_owned()?))
.unwrap_or(true))
}
Prevention
- Process repeated rebase ranges root-to-tip so parents are settled before descendants
- Re-check pending state of neighboring commits before each edit
- Avoid overlapping repeated ranges in one script run
When it happens
Trigger: Calling a repeated rebase edit where `graph.parents_of(*base)` yields a first parent whose decoded commit satisfies `is_pending()`. I.e. the base of the repeated rebase hangs directly under another pending commit.
Common situations: Chaining repeated rebase edits across overlapping ranges; editing a range whose base commit was itself just rewritten but left pending; rebase scripts that operate on adjacent segments of the same pending stack in the wrong order.
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
- the root of a repeated rebase must be pending
- the current checkout has a pending rebase; time-travel to…
- has a pending rebase
- the rebase state contains duplicate scope commits
- the rebase state contains duplicate tips
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/4f6e82acd7145577.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/rebase.rs:2561
) -> Result<()> {
for (position, id) in affected.iter().enumerate() {
let parents = graph.parents_of(*id).context("an affected commit is incomplete")?;
if parents.len() > 1 && (position > 0 || removed || tree == Tree::CherryPick) {
anyhow::bail!("descendant merge commits cannot be rebased");
}
if repeat && position == 0 {
let commit = repo.find_commit(*id)?.decode()?.into_owned()?;
if !is_pending(&commit) {
anyhow::bail!("the root of a repeated rebase must be pending");
}
}
}
if repeat
&& let Some(base) = affected.first()
&& let Some(parent) = graph.parents_of(*base).and_then(|parents| parents.first().copied())
&& is_pending(&repo.find_commit(parent)?.decode()?.into_owned()?)
{
anyhow::bail!("the parent of a repeated rebase must not be pending");
}
Ok(())
}
fn reject_pending_checkout_path(repo: &gix::Repository, mut id: ObjectId) -> Result<()> {
let mut seen = HashSet::new();
while seen.insert(id) {
let commit = repo.find_commit(id)?.decode()?.into_owned()?;
if is_pending(&commit) {
anyhow::bail!("the current checkout has a pending rebase; time-travel to HEAD before editing it");
}
let Some(parent) = commit.parents.first().copied() else {
break;
};
id = parent;
}
Ok(())
}View on GitHub (pinned to e73179060b)