GitoxideLabs/gitoxide · error
the @ command and @ reference point to different results
Error message
the @ command and @ reference point to different results
What it means
Thrown when both the `@`-marked command and an `@`-style reference in the todo resolve to different plan steps. The single checkout target must be consistent: the marker and any `@` reference to it must point at the same resulting step.
Solutions
- Make the `@` reference and the `@`-marked command point at the same step
- Keep only one `@` marker and update all references to match its result
- Regenerate the todo instead of hand-editing marker placement
Example fix
// before @pick abc123 pick def456 squash ghi789 @ # refers to a different result // after pick abc123 @pick def456 squash ghi789 @ # now consistent
Defensive patterns
Strategy: validation
Validate before calling
// ensure every @ reference resolves to the same step as the single @-marked command
if marked_lines.len() > 1 || (marked_command_line != referenced_line) {
anyhow::bail!("@ marker and @ reference must point at the same result");
} Type guard
fn targets_consistent(marker_step: usize, reference_step: Option<usize>) -> bool {
reference_step.map_or(true, |r| r == marker_step)
} Try / catch
match parse_plan(...) {
Err(e) if e.to_string().contains("point to different results") => { /* realign marker and reference */ }
other => other?,
} Prevention
- Place the `@` marker only on the command that the `@` reference targets
- Change marker and references together in one edit
- Validate todo consistency before parsing
When it happens
Trigger: `parse_plan` processes an `@`-marked squash or command whose computed `PlanParent::Step(index)` differs from a previously recorded `checkout_target`.
Common situations: Marking one command with `@` while an `@` reference elsewhere in the todo points at another command's result; hand-editing that moved the marker without moving the reference.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- rebase todo requires at least one -x/--hide revision when…
- the hidden and visible revisions have no editable fork point
- the revisions have multiple editable fork points
- aborted without changes: conflict while applying ; pass…
- an edit unexpectedly produced a merge conflict
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/550c220a46e934a7.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/todo.rs:950
}
}
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);
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;
continue;
}
let parent = cursor.context("the first todo command must follow a fork heading")?;
let commit = match verb {
"pick" => {
let value = value.split_whitespace().next().context("a pick needs a commit ID")?;
let resolved_id = state.resolved;
let full_null = resolved_id.is_some_and(|id| {
value.len() == id.kind().len_in_bytes() * 2 && value.bytes().all(|byte| byte == b'0')
});
let (id, resolved) = if full_null {
(
resolved_id.context("a null pick has no materialized conflict state")?,
true,View on GitHub (pinned to e73179060b)