{"record":{"id":"912c412c3673c2d6","repo":"jesseduffield/lazygit","slug":"expected-exactly-one-original-hash-found-d","errorCode":null,"errorMessage":"Expected exactly one original hash, found %d","messagePattern":"Expected exactly one original hash, found (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/utils/rebase_todo.go","lineNumber":258,"sourceCode":"\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn WriteRebaseTodoFile(fileName, newTodos, commentChar)\n}\n\nfunc moveFixupCommitDown(todos []todo.Todo, originalHash string, fixupHash string, changeToFixup bool) ([]todo.Todo, error) {\n\tisOriginal := func(t todo.Todo) bool {\n\t\treturn (t.Command == todo.Pick || t.Command == todo.Merge) && equalHash(t.Commit, originalHash)\n\t}\n\n\tisFixup := func(t todo.Todo) bool {\n\t\treturn t.Command == todo.Pick && equalHash(t.Commit, fixupHash)\n\t}\n\n\toriginalHashCount := lo.CountBy(todos, isOriginal)\n\tif originalHashCount != 1 {\n\t\treturn nil, fmt.Errorf(\"Expected exactly one original hash, found %d\", originalHashCount)\n\t}\n\n\tfixupHashCount := lo.CountBy(todos, isFixup)\n\tif fixupHashCount != 1 {\n\t\treturn nil, fmt.Errorf(\"Expected exactly one fixup hash, found %d\", fixupHashCount)\n\t}\n\n\t_, fixupIndex, _ := lo.FindIndexOf(todos, isFixup)\n\t_, originalIndex, _ := lo.FindIndexOf(todos, isOriginal)\n\n\tnewTodos := MoveElement(todos, fixupIndex, originalIndex+1)\n\n\tif changeToFixup {\n\t\tnewTodos[originalIndex+1].Command = todo.Fixup\n\t}\n\n\treturn newTodos, nil\n}","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/jesseduffield/lazygit/blob/c477a2959b229fbf3284be0d4d2904ab61ec3c94/pkg/utils/rebase_todo.go#L240-L276","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# sanity check before fixup: original hash appears exactly once as pick or merge -C\ngrep -cE \"^(pick|merge -C) ${FULL_HASH}\" .git/rebase-merge/git-rebase-todo  # want exactly 1","typeGuard":null,"tryCatchPattern":"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).","preventionTips":["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"],"tags":["lazygit","rebase","fixup","squash","git-rebase-todo"],"backgroundTag":null,"analyzedSha":"c477a2959b229fbf3284be0d4d2904ab61ec3c94","analyzedAt":"2026-08-15T08:34:32.451Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}