GitoxideLabs/gitoxide · error

the rebase todo has no fork heading

Error message

the rebase todo has no fork heading

What it means

The interactive-rebase todo parser in gix-tix requires every todo to begin with a `fork <commit-id>` separator heading, which anchors the first section of the plan. If the edited todo text, after stripping comments and blank lines, contains no fork heading at all, `parse` (called via `parse_plan`) aborts with this error. This is a structural validation of user-edited todo content, since the tool only allows editing history between fork points.

Solutions

  1. Reopen the todo and keep at least one `───── fork <commit-id> ─────` heading line above the first command.
  2. Ensure the fork heading is not commented out (it must not start with `# ` or be inside an `<!-- -->` block).
  3. If the edit was accidental, abort/cancel the todo edit and restart the command to regenerate a fresh todo.

Example fix

// before (todo file, no heading)
pick 1a2b3c4d

// after
────── fork 9f8e7d6c some base ──────
pick 1a2b3c4d
Defensive patterns

Strategy: validation

Validate before calling

// Rust: check the edited todo keeps at least one fork heading
let has_fork = text.lines().any(|l| {
    let l = l.trim();
    !l.starts_with('#') && !l.is_empty() && l.starts_with('─') && l.trim_matches('─').trim().starts_with("fork ")
});
if !has_fork {
    return Err("todo must keep at least one `fork <id>` heading");
}

Try / catch

match parse_plan(&repo, text) {
    Ok(plan) => apply(plan),
    Err(e) if e.to_string().contains("no fork heading") => {
        eprintln!("Todo edit removed the required fork heading; regenerating todo.");
        regenerate_todo();
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `parse`/`parse_plan` on todo text where all `─ fork <id> ─` separator lines were deleted by the user in the editor, where the whole file was emptied, or where every remaining line is a comment or blank.

Common situations: A user clears the editor buffer or a misconfigured `$EDITOR`/script overwrites the todo file with empty or template-only content; commenting out everything including the fork heading with `#` or `<!-- -->`.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at gix-tix/src/edit/todo.rs:1015

        }
        steps.push(rebase::PlanStep {
            parent,
            commit,
            squash: Vec::new(),
        });
        cursor = Some(rebase::PlanParent::Step(index));
        section_last_step = Some(index);
        if marked {
            let target = rebase::PlanParent::Step(index);
            if checkout_target.is_some_and(|checkout| checkout != target) {
                anyhow::bail!("the @ command and @ reference point to different results");
            }
            checkout_target = Some(target);
        }
        section_has_commit = true;
    }
    if sections == 0 {
        anyhow::bail!("the rebase todo has no fork heading");
    }
    if sections > 1 && !section_has_commit {
        anyhow::bail!("the last fork section contains no commits");
    }
    if state.marker_required && checkout_target.is_none() {
        anyhow::bail!("the current checkout marker must be retained");
    }
    let checkout_reference = match (checkout_target, explicit_checkout_reference) {
        (Some(target), Some((name, reference_target))) => {
            if target != reference_target {
                anyhow::bail!("the @ command and @ reference point to different results");
            }
            Some(name)
        }
        (None, Some(_)) => anyhow::bail!("an @ reference requires an @ command at the same result"),
        (Some(target), None) => state
            .head_ref
            .take()

View on GitHub (pinned to e73179060b)