GitoxideLabs/gitoxide · error

the revisions have multiple editable fork points

Error message

the revisions have multiple editable fork points: {}

What it means

The counterpart to the zero-candidate case: when `hidden_rebase_candidates()` returns more than one possible fork point, `rebase::prepare` refuses to guess, sorts the candidates by object id for deterministic reporting, and bails listing all of them. The user must narrow the base so exactly one candidate remains.

Solutions

  1. Pass a single, specific `-x/--hide` revision naming the exact intended fork point.
  2. Reduce the number of `-x` revisions to the one that is the true base.
  3. Inspect the candidate ids listed in the message with `gix log` to pick the right one.
  4. Rewrite/linearize the criss-cross history first if appropriate.

Example fix

// before
gix tix rebase todo -x branch-a -x branch-b   # two fork points
// after
gix tix rebase todo -x branch-a   # one explicit fork point
Defensive patterns

Strategy: try-catch

Validate before calling

// Resolve candidate merge bases of the hidden and visible tips first; proceed only when exactly one exists.

Try / catch

match prepare(repo, &args) { Err(e) if e.to_string().contains("multiple editable fork points") => { let base = parse_first_candidate(&e.to_string()); let mut args2 = args.clone(); args2.hide = vec![base]; prepare(repo, &args2) } other => other }

Prevention

When it happens

Trigger: Rebase prepare where the hidden and visible revisions share several merge-base-like candidates — typically when multiple `-x/--hide` revisions are given and they fork at different points, or criss-cross merge history yields multiple equally valid bases.

Common situations: Criss-cross merge topologies from repeated merges between two branches; passing several `-x` revisions from divergent remotes; rebasing a stacked branch whose base history was rewritten inconsistently.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/6fffe5e54fa0ceb4. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/command/rebase.rs:146

            match event {
                Event::Decorations(value) => decorations = value,
                Event::Commits(commits) => app.extend_commits(commits),
                Event::HiddenCommits(commits) => app.extend_hidden_commits(commits),
                Event::Complete(value) => graph = Some(value),
                Event::VisibleComplete | Event::Cancelled => {}
            }
            true
        },
    )?;
    let graph = graph.context("history traversal did not produce a graph")?;
    crate::update_hidden_branch_updates(&mut app, Some(&graph), &refs);
    let mut candidates = app.hidden_rebase_candidates();
    if candidates.len() != 1 {
        if candidates.is_empty() {
            anyhow::bail!("the hidden and visible revisions have no editable fork point");
        }
        candidates.sort_by_key(|(id, _)| *id);
        anyhow::bail!(
            "the revisions have multiple editable fork points: {}",
            candidates
                .iter()
                .map(|(id, _)| id.to_string())
                .collect::<Vec<_>>()
                .join(", ")
        );
    }
    let (base, scope) = candidates.pop().context("one rebase candidate was expected")?;
    let (onto, onto_kind) = if args.update_base {
        let onto = app
            .hidden_branch_update(base)
            .context("--update-base found no newer hidden local branch tip for the derived base")?;
        (onto, todo::OntoKind::UpdatedBase)
    } else {
        (
            args.onto
                .as_deref()

View on GitHub (pinned to e73179060b)