jesseduffield/lazygit · error
Expected exactly one original hash, found %d
Error message
Expected exactly one original hash, found %d
What it means
Returned by moveFixupCommitDown when squashing a fixup: it counts todos whose command is Pick or Merge with the original commit's hash and requires exactly one. Any count other than 1 — zero (original not in todo) or more than one (original appears as both a pick and a 'merge -C' entry, or duplicated picks) — aborts with this error rather than guessing which entry to target.
Source
Thrown at pkg/utils/rebase_todo.go:258
if err != nil {
return err
}
return WriteRebaseTodoFile(fileName, newTodos, commentChar)
}
func moveFixupCommitDown(todos []todo.Todo, originalHash string, fixupHash string, changeToFixup bool) ([]todo.Todo, error) {
isOriginal := func(t todo.Todo) bool {
return (t.Command == todo.Pick || t.Command == todo.Merge) && equalHash(t.Commit, originalHash)
}
isFixup := func(t todo.Todo) bool {
return t.Command == todo.Pick && equalHash(t.Commit, fixupHash)
}
originalHashCount := lo.CountBy(todos, isOriginal)
if originalHashCount != 1 {
return nil, fmt.Errorf("Expected exactly one original hash, found %d", originalHashCount)
}
fixupHashCount := lo.CountBy(todos, isFixup)
if fixupHashCount != 1 {
return nil, fmt.Errorf("Expected exactly one fixup hash, found %d", fixupHashCount)
}
_, fixupIndex, _ := lo.FindIndexOf(todos, isFixup)
_, originalIndex, _ := lo.FindIndexOf(todos, isOriginal)
newTodos := MoveElement(todos, fixupIndex, originalIndex+1)
if changeToFixup {
newTodos[originalIndex+1].Command = todo.Fixup
}
return newTodos, nil
}View on GitHub (pinned to c477a2959b)
Solutions
- Inspect .git-rebase-todo and remove the duplicate/contradictory entry for that hash, then retry the fixup
- Abort the rebase and redo it, squashing before the todo file accumulates duplicates
- Check the reported count: 'found 0' means the original commit isn't part of this rebase at all (wrong base), 'found 2+' means duplication
Defensive patterns
Strategy: validation
Validate before calling
# sanity check before fixup: original hash appears exactly once as pick or merge -C
grep -cE "^(pick|merge -C) ${FULL_HASH}" .git/rebase-merge/git-rebase-todo # want exactly 1 Try / catch
Catch and inspect the count: 0 means wrong base or already-applied original (restart rebase), 2+ means duplicate entries (clean the todo file, then retry).
Prevention
- Check the todo file after any conflict-resolution cycle for duplicated entries before squashing
- Fixup onto plain picks, not onto hashes that also appear in merge -C lines
When it happens
Trigger: Pressing fixup/squash in lazygit during an interactive rebase where the original commit is represented multiple times (e.g. a 'merge -C <hash>' line plus a 'pick <hash>') or is absent from the todo because it was already applied or dropped.
Common situations: Squashing onto a merge commit whose hash also appears in a merge -C line; rebases with duplicated entries after conflict resolution; todo files rewritten by external tooling leaving duplicate picks.
Related errors
- Expected exactly one fixup hash, found %d
- Cannot squash commits in current branch: the HEAD commit is
- Todo %s not found in git-rebase-todo
- Expected exactly one merge commit with hash %s
- index outside of range of commits
AI-assisted analysis of jesseduffield/lazygit@c477a2959b (2026-08-15).
Data as JSON: /api/errors/912c412c3673c2d6.
Report an issue: GitHub.