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
- Remove all but one `@` prefix from the todo, leaving it only on the command whose result should be checked out
- If multiple checkouts are needed, split the operation into several plan edits
- 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
- Keep at most one `@` marker per todo and place it on the final intended checkout command
- Count @-prefixed first tokens before parsing
- Generate todos programmatically instead of hand-editing
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
- an editable commit is not connected to the selected base
- a commit is picked more than once
- an empty commit needs a title
- unsupported rebase todo command
- the rebase todo has no fork heading
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)