GitoxideLabs/gitoxide · error

the rebase todo contains more than one @ command

Error message

the rebase todo contains more than one @ command

What it means

This error is thrown by the rebase todo parser in gix-tix when a todo script marks more than one line with an `@` prefix. The `@` marker selects the result of a command as the checkout target of the edited plan, and exactly one such marker is allowed. The parser uses a `command_marker` flag and bails once a second marked line is seen.

Solutions

  1. Remove all but one `@` prefix from the todo, leaving it only on the command whose result should be checked out
  2. If multiple checkouts are needed, split the operation into several plan edits
  3. Validate the todo text before parsing by counting lines whose first token starts with `@`

Example fix

// before
@pick abc123
@pick def456
// after
@pick abc123
pick def456
Defensive patterns

Strategy: validation

Validate before calling

let marked = todo.lines().filter(|l| l.split_whitespace().next().map_or(false, |v| v.starts_with('@'))).count();
if marked > 1 { anyhow::bail!("todo has {} @-marked commands; only one is allowed", marked); }

Type guard

fn marked_commands(todo: &str) -> Vec<&str> {
    todo.lines().filter(|l| l.split_whitespace().next().map_or(false, |v| v.starts_with('@'))).collect()
}

Try / catch

match parse_plan(...) {
    Err(e) if e.to_string().contains("more than one @ command") => { /* strip extra @ markers and retry */ }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `parse_plan` (via the todo editing API) with a rebase todo file in which two or more lines start with `@` (e.g. `@pick abc123` and `@pick def456`).

Common situations: Hand-editing a rebase todo and marking two commands with `@` by mistake; scripting todo generation where the marker is added per-command instead of only for the final checkout target.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

            }
            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);
        if marked {
            if std::mem::replace(&mut command_marker, true) {
                anyhow::bail!("the rebase todo contains more than one @ command");
            }
            if !state.checkout_allowed || repo.workdir().is_none() {
                anyhow::bail!("the rebase todo cannot select a checkout without a worktree");
            }
        }
        if verb == "squash" {
            let index = section_last_step.context("a squash must follow a command in the same fork")?;
            let id = resolve_commit(
                repo,
                value.split_whitespace().next().context("a squash needs a commit ID")?,
            )?;
            if !scope.contains(&id) {
                anyhow::bail!("a squash is outside the editable history");
            }
            if picked.insert(id, index).is_some() {
                anyhow::bail!("a commit is picked more than once");
            }
            steps[index].squash.push(id);

View on GitHub (pinned to e73179060b)