Add a function to change which commit a rebase todo picks

The next commit uses this to replay a modified copy of a commit in
place of the original one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Stefan Haller
2026-11-03 19:25:48 +01:00
co-authored by Claude Opus 5.5
parent e8261e06d1
commit 09068b0360
2 changed files with 96 additions and 0 deletions
+27
View File
@@ -331,3 +331,30 @@ func dropMergeCommit(todos []todo.Todo, hash string) ([]todo.Todo, error) {
_, idx, _ := lo.FindIndexOf(todos, isMerge)
return slices.Delete(todos, idx, idx+1), nil
}
// Read a git-rebase-todo file, make the todo for the given commit use a
// different commit instead, and write it back
func ChangeTodoCommit(fileName string, hash string, newHash string, commentChar byte) error {
todos, err := ReadRebaseTodoFile(fileName, commentChar)
if err != nil {
return err
}
newTodos, err := changeTodoCommit(todos, hash, newHash)
if err != nil {
return err
}
return WriteRebaseTodoFile(fileName, newTodos, commentChar)
}
func changeTodoCommit(todos []todo.Todo, hash string, newHash string) ([]todo.Todo, error) {
idx, ok := findTodo(todos, Todo{Hash: hash})
if !ok {
// Should never happen
return nil, fmt.Errorf("Todo %s not found in git-rebase-todo", hash)
}
todos[idx].Commit = newHash
return todos, nil
}
+69
View File
@@ -596,6 +596,75 @@ func TestRebaseCommands_deleteTodos(t *testing.T) {
}
}
func TestRebaseCommands_changeTodoCommit(t *testing.T) {
scenarios := []struct {
name string
todos []todo.Todo
hash string
newHash string
expectedTodos []todo.Todo
expectedErr error
}{
{
name: "success",
todos: []todo.Todo{
{Command: todo.Pick, Commit: "1234", Msg: "first"},
{Command: todo.Pick, Commit: "5678", Msg: "second"},
{Command: todo.UpdateRef, Ref: "refs/heads/some_branch"},
{Command: todo.Pick, Commit: "abcd", Msg: "third"},
},
hash: "5678",
newHash: "ef01",
expectedTodos: []todo.Todo{
{Command: todo.Pick, Commit: "1234", Msg: "first"},
{Command: todo.Pick, Commit: "ef01", Msg: "second"},
{Command: todo.UpdateRef, Ref: "refs/heads/some_branch"},
{Command: todo.Pick, Commit: "abcd", Msg: "third"},
},
expectedErr: nil,
},
{
name: "abbreviated hash in todo",
todos: []todo.Todo{
{Command: todo.Pick, Commit: "1234"},
{Command: todo.Pick, Commit: "5678"},
},
hash: "56789abc",
newHash: "ef01",
expectedTodos: []todo.Todo{
{Command: todo.Pick, Commit: "1234"},
{Command: todo.Pick, Commit: "ef01"},
},
expectedErr: nil,
},
{
name: "failure",
todos: []todo.Todo{
{Command: todo.Pick, Commit: "1234"},
{Command: todo.Pick, Commit: "5678"},
},
hash: "abcd",
newHash: "ef01",
expectedTodos: nil,
expectedErr: errors.New("Todo abcd not found in git-rebase-todo"),
},
}
for _, scenario := range scenarios {
t.Run(scenario.name, func(t *testing.T) {
actualTodos, actualErr := changeTodoCommit(scenario.todos, scenario.hash, scenario.newHash)
if scenario.expectedErr == nil {
assert.NoError(t, actualErr)
} else {
assert.EqualError(t, actualErr, scenario.expectedErr.Error())
}
assert.EqualValues(t, scenario.expectedTodos, actualTodos)
})
}
}
func Test_equalHash(t *testing.T) {
scenarios := []struct {
a string