mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-25 12:24:47 +02:00
Fix deleting update ref todos (#3439)
- **PR Description** Deleting an update-ref todo in an interactive rebase now behaves as expected (i.e. it leaves the branch referenced by the update-ref untouched). Previously it would have deleted the branch referenced by the update-ref todo when the rebase was continued. See #3418 for more details. Fixes #3418.
This commit is contained in:
commit
e295ccefab
@ -39,6 +39,7 @@ const (
|
|||||||
DaemonKindInsertBreak
|
DaemonKindInsertBreak
|
||||||
DaemonKindChangeTodoActions
|
DaemonKindChangeTodoActions
|
||||||
DaemonKindMoveFixupCommitDown
|
DaemonKindMoveFixupCommitDown
|
||||||
|
DaemonKindWriteRebaseTodo
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -59,6 +60,7 @@ func getInstruction() Instruction {
|
|||||||
DaemonKindMoveTodosUp: deserializeInstruction[*MoveTodosUpInstruction],
|
DaemonKindMoveTodosUp: deserializeInstruction[*MoveTodosUpInstruction],
|
||||||
DaemonKindMoveTodosDown: deserializeInstruction[*MoveTodosDownInstruction],
|
DaemonKindMoveTodosDown: deserializeInstruction[*MoveTodosDownInstruction],
|
||||||
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
|
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
|
||||||
|
DaemonKindWriteRebaseTodo: deserializeInstruction[*WriteRebaseTodoInstruction],
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapping[getDaemonKind()](jsonData)
|
return mapping[getDaemonKind()](jsonData)
|
||||||
@ -330,3 +332,27 @@ func (self *InsertBreakInstruction) run(common *common.Common) error {
|
|||||||
return utils.PrependStrToTodoFile(path, []byte("break\n"))
|
return utils.PrependStrToTodoFile(path, []byte("break\n"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WriteRebaseTodoInstruction struct {
|
||||||
|
TodosFileContent []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWriteRebaseTodoInstruction(todosFileContent []byte) Instruction {
|
||||||
|
return &WriteRebaseTodoInstruction{
|
||||||
|
TodosFileContent: todosFileContent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WriteRebaseTodoInstruction) Kind() DaemonKind {
|
||||||
|
return DaemonKindWriteRebaseTodo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WriteRebaseTodoInstruction) SerializedInstructions() string {
|
||||||
|
return serializeInstruction(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WriteRebaseTodoInstruction) run(common *common.Common) error {
|
||||||
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
|
return os.WriteFile(path, self.TodosFileContent, 0o644)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -204,7 +204,7 @@ type PrepareInteractiveRebaseCommandOpts struct {
|
|||||||
|
|
||||||
// PrepareInteractiveRebaseCommand returns the cmd for an interactive rebase
|
// PrepareInteractiveRebaseCommand returns the cmd for an interactive rebase
|
||||||
// we tell git to run lazygit to edit the todo list, and we pass the client
|
// we tell git to run lazygit to edit the todo list, and we pass the client
|
||||||
// lazygit a todo string to write to the todo file
|
// lazygit instructions what to do with the todo file
|
||||||
func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteractiveRebaseCommandOpts) oscommands.ICmdObj {
|
func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteractiveRebaseCommandOpts) oscommands.ICmdObj {
|
||||||
ex := oscommands.GetLazygitPath()
|
ex := oscommands.GetLazygitPath()
|
||||||
|
|
||||||
@ -250,6 +250,36 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
|
|||||||
return cmdObj
|
return cmdObj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GitRebaseEditTodo runs "git rebase --edit-todo", saving the given todosFileContent to the file
|
||||||
|
func (self *RebaseCommands) GitRebaseEditTodo(todosFileContent []byte) error {
|
||||||
|
ex := oscommands.GetLazygitPath()
|
||||||
|
|
||||||
|
cmdArgs := NewGitCmd("rebase").
|
||||||
|
Arg("--edit-todo").
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
debug := "FALSE"
|
||||||
|
if self.Debug {
|
||||||
|
debug = "TRUE"
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Log.WithField("command", cmdArgs).Debug("RunCommand")
|
||||||
|
|
||||||
|
cmdObj := self.cmd.New(cmdArgs)
|
||||||
|
|
||||||
|
cmdObj.AddEnvVars(daemon.ToEnvVars(daemon.NewWriteRebaseTodoInstruction(todosFileContent))...)
|
||||||
|
|
||||||
|
cmdObj.AddEnvVars(
|
||||||
|
"DEBUG="+debug,
|
||||||
|
"LANG=en_US.UTF-8", // Force using EN as language
|
||||||
|
"LC_ALL=en_US.UTF-8", // Force using EN as language
|
||||||
|
"GIT_EDITOR="+ex,
|
||||||
|
"GIT_SEQUENCE_EDITOR="+ex,
|
||||||
|
)
|
||||||
|
|
||||||
|
return cmdObj.Run()
|
||||||
|
}
|
||||||
|
|
||||||
// AmendTo amends the given commit with whatever files are staged
|
// AmendTo amends the given commit with whatever files are staged
|
||||||
func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) error {
|
func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) error {
|
||||||
commit := commits[commitIndex]
|
commit := commits[commitIndex]
|
||||||
@ -302,11 +332,16 @@ func (self *RebaseCommands) DeleteUpdateRefTodos(commits []*models.Commit) error
|
|||||||
return todoFromCommit(commit)
|
return todoFromCommit(commit)
|
||||||
})
|
})
|
||||||
|
|
||||||
return utils.DeleteTodos(
|
todosFileContent, err := utils.DeleteTodos(
|
||||||
filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"),
|
filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"),
|
||||||
todosToDelete,
|
todosToDelete,
|
||||||
self.config.GetCoreCommentChar(),
|
self.config.GetCoreCommentChar(),
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.GitRebaseEditTodo(todosFileContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) MoveTodosDown(commits []*models.Commit) error {
|
func (self *RebaseCommands) MoveTodosDown(commits []*models.Commit) error {
|
||||||
|
@ -50,6 +50,8 @@ var DeleteUpdateRefTodo = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Contains("pick").Contains("CI commit 02"),
|
Contains("pick").Contains("CI commit 02"),
|
||||||
Contains("CI ◯ <-- YOU ARE HERE --- commit 01"),
|
Contains("CI ◯ <-- YOU ARE HERE --- commit 01"),
|
||||||
).
|
).
|
||||||
|
NavigateToLine(Contains("commit 02")).
|
||||||
|
Press(keys.Universal.Remove).
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.Common().ContinueRebase()
|
t.Common().ContinueRebase()
|
||||||
}).
|
}).
|
||||||
@ -57,9 +59,14 @@ var DeleteUpdateRefTodo = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Contains("CI ◯ commit 06"),
|
Contains("CI ◯ commit 06"),
|
||||||
Contains("CI ◯ commit 05"),
|
Contains("CI ◯ commit 05"),
|
||||||
Contains("CI ◯ commit 04"),
|
Contains("CI ◯ commit 04"),
|
||||||
Contains("CI ◯ commit 03"), // No start on this commit, so there's no branch head here
|
Contains("CI ◯ commit 03"), // No star on this commit, so there's no branch head here
|
||||||
Contains("CI ◯ commit 02"),
|
|
||||||
Contains("CI ◯ commit 01"),
|
Contains("CI ◯ commit 01"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
t.Views().Branches().
|
||||||
|
Lines(
|
||||||
|
Contains("branch2"),
|
||||||
|
Contains("branch1"),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@ -96,6 +97,12 @@ func WriteRebaseTodoFile(fileName string, todos []todo.Todo, commentChar byte) e
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func todosToString(todos []todo.Todo, commentChar byte) ([]byte, error) {
|
||||||
|
buffer := bytes.Buffer{}
|
||||||
|
err := todo.Write(&buffer, todos, commentChar)
|
||||||
|
return buffer.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
func PrependStrToTodoFile(filePath string, linesToPrepend []byte) error {
|
func PrependStrToTodoFile(filePath string, linesToPrepend []byte) error {
|
||||||
existingContent, err := os.ReadFile(filePath)
|
existingContent, err := os.ReadFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -106,16 +113,21 @@ func PrependStrToTodoFile(filePath string, linesToPrepend []byte) error {
|
|||||||
return os.WriteFile(filePath, linesToPrepend, 0o644)
|
return os.WriteFile(filePath, linesToPrepend, 0o644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteTodos(fileName string, todosToDelete []Todo, commentChar byte) error {
|
// Unlike the other functions in this file, which write the changed todos file
|
||||||
|
// back to disk, this one returns the new content as a byte slice. This is
|
||||||
|
// because when deleting update-ref todos, we must perform a "git rebase
|
||||||
|
// --edit-todo" command to pass the changed todos to git so that it can do some
|
||||||
|
// housekeeping around the deleted todos. This can only be done by our caller.
|
||||||
|
func DeleteTodos(fileName string, todosToDelete []Todo, commentChar byte) ([]byte, error) {
|
||||||
todos, err := ReadRebaseTodoFile(fileName, commentChar)
|
todos, err := ReadRebaseTodoFile(fileName, commentChar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
rearrangedTodos, err := deleteTodos(todos, todosToDelete)
|
rearrangedTodos, err := deleteTodos(todos, todosToDelete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
return WriteRebaseTodoFile(fileName, rearrangedTodos, commentChar)
|
return todosToString(rearrangedTodos, commentChar)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteTodos(todos []todo.Todo, todosToDelete []Todo) ([]todo.Todo, error) {
|
func deleteTodos(todos []todo.Todo, todosToDelete []Todo) ([]todo.Todo, error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user