GitoxideLabs/gitoxide · error

the rebase todo contains more than one @ reference

Error message

the rebase todo contains more than one @ reference

What it means

Validation inside `edit::todo::parse`, which turns a user-edited rebase-todo file into a `rebase::Plan`. When parsing a `(ref)` line that follows a fork or command heading, each resolved reference name is inserted into `ref_targets`; a duplicate name means the user placed the same reference more than once in the todo. The plan would otherwise silently drop or ambiguously apply reference moves, so parsing aborts. Triggered by hand-edited todo files with repeated ref lines; the fix is to remove the duplicate reference entry so each branch/HEAD is positioned at most once.

Solutions

  1. Keep `@` on exactly one reference line and remove it from the others
  2. Decide which branch/commit should be checked out after the rebase and mark only that one
  3. Reopen the todo to regenerate the template and reapply a single `@` marker

Example fix

// before
(main @)
(feature @)
// after
(main @)
(feature)
Defensive patterns

Strategy: validation

Validate before calling

let markers = ref_lines(edited).filter(|l| l.contains("@")).count();
if markers > 1 {
    return Err("only one @ checkout selection is allowed");
}

Try / catch

if let Err(e) = parse(repo, edited) {
    if e.to_string().contains("more than one @ reference") {
        // ask the user which single ref to check out
    }
}

Prevention

When it happens

Trigger: `parse` bails when `explicit_checkout_reference.replace((name, target))` returns Some — i.e. a second `@`-marked reference line was encountered after one was already recorded. Happens when a user marks multiple refs with `@` while editing the todo.

Common situations: Marking several branch lines with `@` to 'check out wherever'; copy-paste duplication of a marked line; misunderstanding the single-checkout rule.

Related errors


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

Appendix: source

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

            });
            sections += 1;
            section_has_commit = false;
            section_last_step = None;
            continue;
        }
        if line.starts_with('(') && line.ends_with(')') {
            let target = cursor.context("a reference line must follow a fork or command")?;
            for (marked, value) in parse_ref_line(line)? {
                let name = resolve_ref_name(repo, &mut state.expected_refs, value.as_bstr())?;
                if ref_targets.insert(name.clone(), target).is_some() {
                    anyhow::bail!("a reference is placed more than once");
                }
                if marked {
                    if !state.checkout_allowed || repo.workdir().is_none() {
                        anyhow::bail!("the rebase todo cannot select a checkout without a worktree");
                    }
                    if explicit_checkout_reference.replace((name, target)).is_some() {
                        anyhow::bail!("the rebase todo contains more than one @ reference");
                    }
                }
            }
            section_has_commit = true;
            continue;
        }

        let (command, tail) = if let Some(line) = line.strip_prefix('`') {
            let (command, tail) = line
                .split_once('`')
                .context("a Markdown todo command has no closing backtick")?;
            (command, tail.trim())
        } else {
            (line, "")
        };
        let (verb, value) = command.split_once(char::is_whitespace).unwrap_or((command, ""));
        let marked = verb.starts_with('@');
        let verb = verb.strip_prefix('@').unwrap_or(verb);

View on GitHub (pinned to e73179060b)