mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-11-28 09:08:41 +02:00
Support range select in rebase actions
This commit is contained in:
parent
44e2542e4a
commit
f0de880136
@ -34,8 +34,8 @@ const (
|
|||||||
|
|
||||||
DaemonKindExitImmediately
|
DaemonKindExitImmediately
|
||||||
DaemonKindCherryPick
|
DaemonKindCherryPick
|
||||||
DaemonKindMoveTodoUp
|
DaemonKindMoveTodosUp
|
||||||
DaemonKindMoveTodoDown
|
DaemonKindMoveTodosDown
|
||||||
DaemonKindInsertBreak
|
DaemonKindInsertBreak
|
||||||
DaemonKindChangeTodoActions
|
DaemonKindChangeTodoActions
|
||||||
DaemonKindMoveFixupCommitDown
|
DaemonKindMoveFixupCommitDown
|
||||||
@ -56,8 +56,8 @@ func getInstruction() Instruction {
|
|||||||
DaemonKindCherryPick: deserializeInstruction[*CherryPickCommitsInstruction],
|
DaemonKindCherryPick: deserializeInstruction[*CherryPickCommitsInstruction],
|
||||||
DaemonKindChangeTodoActions: deserializeInstruction[*ChangeTodoActionsInstruction],
|
DaemonKindChangeTodoActions: deserializeInstruction[*ChangeTodoActionsInstruction],
|
||||||
DaemonKindMoveFixupCommitDown: deserializeInstruction[*MoveFixupCommitDownInstruction],
|
DaemonKindMoveFixupCommitDown: deserializeInstruction[*MoveFixupCommitDownInstruction],
|
||||||
DaemonKindMoveTodoUp: deserializeInstruction[*MoveTodoUpInstruction],
|
DaemonKindMoveTodosUp: deserializeInstruction[*MoveTodosUpInstruction],
|
||||||
DaemonKindMoveTodoDown: deserializeInstruction[*MoveTodoDownInstruction],
|
DaemonKindMoveTodosDown: deserializeInstruction[*MoveTodosDownInstruction],
|
||||||
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
|
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,13 +208,15 @@ func (self *ChangeTodoActionsInstruction) SerializedInstructions() string {
|
|||||||
|
|
||||||
func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
|
func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
|
||||||
return handleInteractiveRebase(common, func(path string) error {
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
for _, c := range self.Changes {
|
changes := lo.Map(self.Changes, func(c ChangeTodoAction, _ int) utils.TodoChange {
|
||||||
if err := utils.EditRebaseTodo(path, c.Sha, todo.Pick, c.NewAction, getCommentChar()); err != nil {
|
return utils.TodoChange{
|
||||||
return err
|
Sha: c.Sha,
|
||||||
|
OldAction: todo.Pick,
|
||||||
|
NewAction: c.NewAction,
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
return nil
|
return utils.EditRebaseTodo(path, changes, getCommentChar())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,51 +249,65 @@ func (self *MoveFixupCommitDownInstruction) run(common *common.Common) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type MoveTodoUpInstruction struct {
|
type MoveTodosUpInstruction struct {
|
||||||
Sha string
|
Shas []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMoveTodoUpInstruction(sha string) Instruction {
|
func NewMoveTodosUpInstruction(shas []string) Instruction {
|
||||||
return &MoveTodoUpInstruction{
|
return &MoveTodosUpInstruction{
|
||||||
Sha: sha,
|
Shas: shas,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoUpInstruction) Kind() DaemonKind {
|
func (self *MoveTodosUpInstruction) Kind() DaemonKind {
|
||||||
return DaemonKindMoveTodoUp
|
return DaemonKindMoveTodosUp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoUpInstruction) SerializedInstructions() string {
|
func (self *MoveTodosUpInstruction) SerializedInstructions() string {
|
||||||
return serializeInstruction(self)
|
return serializeInstruction(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoUpInstruction) run(common *common.Common) error {
|
func (self *MoveTodosUpInstruction) run(common *common.Common) error {
|
||||||
|
todosToMove := lo.Map(self.Shas, func(sha string, _ int) utils.Todo {
|
||||||
|
return utils.Todo{
|
||||||
|
Sha: sha,
|
||||||
|
Action: todo.Pick,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return handleInteractiveRebase(common, func(path string) error {
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
return utils.MoveTodoUp(path, self.Sha, todo.Pick, getCommentChar())
|
return utils.MoveTodosUp(path, todosToMove, getCommentChar())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type MoveTodoDownInstruction struct {
|
type MoveTodosDownInstruction struct {
|
||||||
Sha string
|
Shas []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMoveTodoDownInstruction(sha string) Instruction {
|
func NewMoveTodosDownInstruction(shas []string) Instruction {
|
||||||
return &MoveTodoDownInstruction{
|
return &MoveTodosDownInstruction{
|
||||||
Sha: sha,
|
Shas: shas,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoDownInstruction) Kind() DaemonKind {
|
func (self *MoveTodosDownInstruction) Kind() DaemonKind {
|
||||||
return DaemonKindMoveTodoDown
|
return DaemonKindMoveTodosDown
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoDownInstruction) SerializedInstructions() string {
|
func (self *MoveTodosDownInstruction) SerializedInstructions() string {
|
||||||
return serializeInstruction(self)
|
return serializeInstruction(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoDownInstruction) run(common *common.Common) error {
|
func (self *MoveTodosDownInstruction) run(common *common.Common) error {
|
||||||
|
todosToMove := lo.Map(self.Shas, func(sha string, _ int) utils.Todo {
|
||||||
|
return utils.Todo{
|
||||||
|
Sha: sha,
|
||||||
|
Action: todo.Pick,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return handleInteractiveRebase(common, func(path string) error {
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
return utils.MoveTodoDown(path, self.Sha, todo.Pick, getCommentChar())
|
return utils.MoveTodosDown(path, todosToMove, getCommentChar())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,58 +105,49 @@ func (self *RebaseCommands) GenericAmend(commits []*models.Commit, index int, f
|
|||||||
return self.ContinueRebase()
|
return self.ContinueRebase()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) MoveCommitDown(commits []*models.Commit, index int) error {
|
func (self *RebaseCommands) MoveCommitsDown(commits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
baseShaOrRoot := getBaseShaOrRoot(commits, index+2)
|
baseShaOrRoot := getBaseShaOrRoot(commits, endIdx+2)
|
||||||
|
|
||||||
sha := commits[index].Sha
|
shas := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
|
||||||
|
return commit.Sha
|
||||||
msg := utils.ResolvePlaceholderString(
|
})
|
||||||
self.Tr.Log.MoveCommitDown,
|
|
||||||
map[string]string{
|
|
||||||
"shortSha": utils.ShortSha(sha),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.os.LogCommand(msg, false)
|
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: baseShaOrRoot,
|
baseShaOrRoot: baseShaOrRoot,
|
||||||
instruction: daemon.NewMoveTodoDownInstruction(sha),
|
instruction: daemon.NewMoveTodosDownInstruction(shas),
|
||||||
overrideEditor: true,
|
overrideEditor: true,
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) MoveCommitUp(commits []*models.Commit, index int) error {
|
func (self *RebaseCommands) MoveCommitsUp(commits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
baseShaOrRoot := getBaseShaOrRoot(commits, index+1)
|
baseShaOrRoot := getBaseShaOrRoot(commits, endIdx+1)
|
||||||
|
|
||||||
sha := commits[index].Sha
|
shas := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
|
||||||
|
return commit.Sha
|
||||||
msg := utils.ResolvePlaceholderString(
|
})
|
||||||
self.Tr.Log.MoveCommitUp,
|
|
||||||
map[string]string{
|
|
||||||
"shortSha": utils.ShortSha(sha),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.os.LogCommand(msg, false)
|
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: baseShaOrRoot,
|
baseShaOrRoot: baseShaOrRoot,
|
||||||
instruction: daemon.NewMoveTodoUpInstruction(sha),
|
instruction: daemon.NewMoveTodosUpInstruction(shas),
|
||||||
overrideEditor: true,
|
overrideEditor: true,
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, index int, action todo.TodoCommand) error {
|
func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, startIdx int, endIdx int, action todo.TodoCommand) error {
|
||||||
baseIndex := index + 1
|
baseIndex := endIdx + 1
|
||||||
if action == todo.Squash || action == todo.Fixup {
|
if action == todo.Squash || action == todo.Fixup {
|
||||||
baseIndex++
|
baseIndex++
|
||||||
}
|
}
|
||||||
|
|
||||||
baseShaOrRoot := getBaseShaOrRoot(commits, baseIndex)
|
baseShaOrRoot := getBaseShaOrRoot(commits, baseIndex)
|
||||||
|
|
||||||
changes := []daemon.ChangeTodoAction{{
|
changes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) daemon.ChangeTodoAction {
|
||||||
Sha: commits[index].Sha,
|
return daemon.ChangeTodoAction{
|
||||||
NewAction: action,
|
Sha: commit.Sha,
|
||||||
}}
|
NewAction: action,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
self.os.LogCommand(logTodoChanges(changes), false)
|
self.os.LogCommand(logTodoChanges(changes), false)
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
@ -200,7 +191,7 @@ func logTodoChanges(changes []daemon.ChangeTodoAction) string {
|
|||||||
changeTodoStr := strings.Join(lo.Map(changes, func(c daemon.ChangeTodoAction, _ int) string {
|
changeTodoStr := strings.Join(lo.Map(changes, func(c daemon.ChangeTodoAction, _ int) string {
|
||||||
return fmt.Sprintf("%s:%s", c.Sha, c.NewAction)
|
return fmt.Sprintf("%s:%s", c.Sha, c.NewAction)
|
||||||
}), "\n")
|
}), "\n")
|
||||||
return fmt.Sprintf("Changing TODO actions: %s", changeTodoStr)
|
return fmt.Sprintf("Changing TODO actions:\n%s", changeTodoStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrepareInteractiveRebaseCommandOpts struct {
|
type PrepareInteractiveRebaseCommandOpts struct {
|
||||||
@ -281,22 +272,45 @@ func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) e
|
|||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditRebaseTodo sets the action for a given rebase commit in the git-rebase-todo file
|
// Sets the action for the given commits in the git-rebase-todo file
|
||||||
func (self *RebaseCommands) EditRebaseTodo(commit *models.Commit, action todo.TodoCommand) error {
|
func (self *RebaseCommands) EditRebaseTodo(commits []*models.Commit, action todo.TodoCommand) error {
|
||||||
|
commitsWithAction := lo.Map(commits, func(commit *models.Commit, _ int) utils.TodoChange {
|
||||||
|
return utils.TodoChange{
|
||||||
|
Sha: commit.Sha,
|
||||||
|
OldAction: commit.Action,
|
||||||
|
NewAction: action,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return utils.EditRebaseTodo(
|
return utils.EditRebaseTodo(
|
||||||
filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"), commit.Sha, commit.Action, action, self.config.GetCoreCommentChar())
|
filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"),
|
||||||
|
commitsWithAction,
|
||||||
|
self.config.GetCoreCommentChar(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveTodoDown moves a rebase todo item down by one position
|
func (self *RebaseCommands) MoveTodosDown(commits []*models.Commit) error {
|
||||||
func (self *RebaseCommands) MoveTodoDown(commit *models.Commit) error {
|
|
||||||
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
|
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
|
||||||
return utils.MoveTodoDown(fileName, commit.Sha, commit.Action, self.config.GetCoreCommentChar())
|
todosToMove := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
|
||||||
|
return utils.Todo{
|
||||||
|
Sha: commit.Sha,
|
||||||
|
Action: commit.Action,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return utils.MoveTodosDown(fileName, todosToMove, self.config.GetCoreCommentChar())
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveTodoDown moves a rebase todo item down by one position
|
func (self *RebaseCommands) MoveTodosUp(commits []*models.Commit) error {
|
||||||
func (self *RebaseCommands) MoveTodoUp(commit *models.Commit) error {
|
|
||||||
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
|
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
|
||||||
return utils.MoveTodoUp(fileName, commit.Sha, commit.Action, self.config.GetCoreCommentChar())
|
todosToMove := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
|
||||||
|
return utils.Todo{
|
||||||
|
Sha: commit.Sha,
|
||||||
|
Action: commit.Action,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return utils.MoveTodosUp(fileName, todosToMove, self.config.GetCoreCommentChar())
|
||||||
}
|
}
|
||||||
|
|
||||||
// SquashAllAboveFixupCommits squashes all fixup! commits above the given one
|
// SquashAllAboveFixupCommits squashes all fixup! commits above the given one
|
||||||
|
@ -2,6 +2,8 @@ package helpers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
@ -80,6 +82,19 @@ func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command))
|
self.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command))
|
||||||
|
if status == enums.REBASE_MODE_REBASING {
|
||||||
|
todoFile, err := os.ReadFile(
|
||||||
|
filepath.Join(self.c.Git().RepoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.c.LogCommand(string(todoFile), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
commandType := ""
|
commandType := ""
|
||||||
switch status {
|
switch status {
|
||||||
|
@ -45,6 +45,7 @@ func NewLocalCommitsController(
|
|||||||
c,
|
c,
|
||||||
c.Contexts().LocalCommits,
|
c.Contexts().LocalCommits,
|
||||||
c.Contexts().LocalCommits.GetSelected,
|
c.Contexts().LocalCommits.GetSelected,
|
||||||
|
c.Contexts().LocalCommits.GetSelectedItems,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,17 +56,23 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||||||
outsideFilterModeBindings := []*types.Binding{
|
outsideFilterModeBindings := []*types.Binding{
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Commits.SquashDown),
|
Key: opts.GetKey(opts.Config.Commits.SquashDown),
|
||||||
Handler: self.withItem(self.squashDown),
|
Handler: self.withItemsRange(self.squashDown),
|
||||||
GetDisabledReason: self.require(
|
GetDisabledReason: self.require(
|
||||||
self.singleItemSelected(self.getDisabledReasonForSquashDown),
|
self.itemRangeSelected(
|
||||||
|
self.midRebaseCommandEnabled,
|
||||||
|
self.canSquashOrFixup,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Description: self.c.Tr.SquashDown,
|
Description: self.c.Tr.SquashDown,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Commits.MarkCommitAsFixup),
|
Key: opts.GetKey(opts.Config.Commits.MarkCommitAsFixup),
|
||||||
Handler: self.withItem(self.fixup),
|
Handler: self.withItemsRange(self.fixup),
|
||||||
GetDisabledReason: self.require(
|
GetDisabledReason: self.require(
|
||||||
self.singleItemSelected(self.getDisabledReasonForFixup),
|
self.itemRangeSelected(
|
||||||
|
self.midRebaseCommandEnabled,
|
||||||
|
self.canSquashOrFixup,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Description: self.c.Tr.FixupCommit,
|
Description: self.c.Tr.FixupCommit,
|
||||||
},
|
},
|
||||||
@ -73,7 +80,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||||||
Key: opts.GetKey(opts.Config.Commits.RenameCommit),
|
Key: opts.GetKey(opts.Config.Commits.RenameCommit),
|
||||||
Handler: self.withItem(self.reword),
|
Handler: self.withItem(self.reword),
|
||||||
GetDisabledReason: self.require(
|
GetDisabledReason: self.require(
|
||||||
self.singleItemSelected(self.rebaseCommandEnabled(todo.Reword)),
|
self.singleItemSelected(self.rewordEnabled),
|
||||||
),
|
),
|
||||||
Description: self.c.Tr.RewordCommit,
|
Description: self.c.Tr.RewordCommit,
|
||||||
},
|
},
|
||||||
@ -81,23 +88,26 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||||||
Key: opts.GetKey(opts.Config.Commits.RenameCommitWithEditor),
|
Key: opts.GetKey(opts.Config.Commits.RenameCommitWithEditor),
|
||||||
Handler: self.withItem(self.rewordEditor),
|
Handler: self.withItem(self.rewordEditor),
|
||||||
GetDisabledReason: self.require(
|
GetDisabledReason: self.require(
|
||||||
self.singleItemSelected(self.rebaseCommandEnabled(todo.Reword)),
|
self.singleItemSelected(self.rewordEnabled),
|
||||||
),
|
),
|
||||||
Description: self.c.Tr.RenameCommitEditor,
|
Description: self.c.Tr.RenameCommitEditor,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Universal.Remove),
|
Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||||
Handler: self.withItem(self.drop),
|
Handler: self.withItemsRange(self.drop),
|
||||||
GetDisabledReason: self.require(
|
GetDisabledReason: self.require(
|
||||||
self.singleItemSelected(self.rebaseCommandEnabled(todo.Drop)),
|
self.itemRangeSelected(
|
||||||
|
self.midRebaseCommandEnabled,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Description: self.c.Tr.DeleteCommit,
|
Description: self.c.Tr.DeleteCommit,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(editCommitKey),
|
Key: opts.GetKey(editCommitKey),
|
||||||
Handler: self.withItem(self.edit),
|
Handler: self.withItems(self.edit),
|
||||||
|
// TODO: have disabled reason ensure that if we're not rebasing, we only select one commit
|
||||||
GetDisabledReason: self.require(
|
GetDisabledReason: self.require(
|
||||||
self.singleItemSelected(self.rebaseCommandEnabled(todo.Edit)),
|
self.itemRangeSelected(self.midRebaseCommandEnabled),
|
||||||
),
|
),
|
||||||
Description: self.c.Tr.EditCommit,
|
Description: self.c.Tr.EditCommit,
|
||||||
},
|
},
|
||||||
@ -107,7 +117,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||||||
// when you manually select the base commit.
|
// when you manually select the base commit.
|
||||||
Key: opts.GetKey(opts.Config.Commits.StartInteractiveRebase),
|
Key: opts.GetKey(opts.Config.Commits.StartInteractiveRebase),
|
||||||
Handler: self.withItem(self.quickStartInteractiveRebase),
|
Handler: self.withItem(self.quickStartInteractiveRebase),
|
||||||
GetDisabledReason: self.require(self.notMidRebase, self.canFindCommitForQuickStart),
|
GetDisabledReason: self.require(self.notMidRebase(self.c.Tr.AlreadyRebasing), self.canFindCommitForQuickStart),
|
||||||
Description: self.c.Tr.QuickStartInteractiveRebase,
|
Description: self.c.Tr.QuickStartInteractiveRebase,
|
||||||
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.QuickStartInteractiveRebaseTooltip, map[string]string{
|
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.QuickStartInteractiveRebaseTooltip, map[string]string{
|
||||||
"editKey": keybindings.Label(editCommitKey),
|
"editKey": keybindings.Label(editCommitKey),
|
||||||
@ -115,9 +125,9 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Commits.PickCommit),
|
Key: opts.GetKey(opts.Config.Commits.PickCommit),
|
||||||
Handler: self.withItem(self.pick),
|
Handler: self.withItems(self.pick),
|
||||||
GetDisabledReason: self.require(
|
GetDisabledReason: self.require(
|
||||||
self.singleItemSelected(self.rebaseCommandEnabled(todo.Pick)),
|
self.itemRangeSelected(self.pickEnabled),
|
||||||
),
|
),
|
||||||
Description: self.c.Tr.PickCommit,
|
Description: self.c.Tr.PickCommit,
|
||||||
},
|
},
|
||||||
@ -131,22 +141,28 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||||||
Key: opts.GetKey(opts.Config.Commits.SquashAboveCommits),
|
Key: opts.GetKey(opts.Config.Commits.SquashAboveCommits),
|
||||||
Handler: self.withItem(self.squashAllAboveFixupCommits),
|
Handler: self.withItem(self.squashAllAboveFixupCommits),
|
||||||
GetDisabledReason: self.require(
|
GetDisabledReason: self.require(
|
||||||
self.notMidRebase,
|
self.notMidRebase(self.c.Tr.AlreadyRebasing),
|
||||||
self.singleItemSelected(),
|
self.singleItemSelected(),
|
||||||
),
|
),
|
||||||
Description: self.c.Tr.SquashAboveCommits,
|
Description: self.c.Tr.SquashAboveCommits,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Commits.MoveDownCommit),
|
Key: opts.GetKey(opts.Config.Commits.MoveDownCommit),
|
||||||
Handler: self.withItem(self.moveDown),
|
Handler: self.withItemsRange(self.moveDown),
|
||||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
GetDisabledReason: self.require(self.itemRangeSelected(
|
||||||
Description: self.c.Tr.MoveDownCommit,
|
self.midRebaseCommandEnabled,
|
||||||
|
self.canMoveDown,
|
||||||
|
)),
|
||||||
|
Description: self.c.Tr.MoveDownCommit,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Commits.MoveUpCommit),
|
Key: opts.GetKey(opts.Config.Commits.MoveUpCommit),
|
||||||
Handler: self.withItem(self.moveUp),
|
Handler: self.withItemsRange(self.moveUp),
|
||||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
GetDisabledReason: self.require(self.itemRangeSelected(
|
||||||
Description: self.c.Tr.MoveUpCommit,
|
self.midRebaseCommandEnabled,
|
||||||
|
self.canMoveUp,
|
||||||
|
)),
|
||||||
|
Description: self.c.Tr.MoveUpCommit,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Commits.PasteCommits),
|
Key: opts.GetKey(opts.Config.Commits.PasteCommits),
|
||||||
@ -263,13 +279,9 @@ func secondaryPatchPanelUpdateOpts(c *ControllerCommon) *types.ViewUpdateOpts {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) squashDown(commit *models.Commit) error {
|
func (self *LocalCommitsController) squashDown(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
applied, err := self.handleMidRebaseCommand(todo.Squash, commit)
|
if self.isRebasing() {
|
||||||
if err != nil {
|
return self.updateTodos(todo.Squash, selectedCommits)
|
||||||
return err
|
|
||||||
}
|
|
||||||
if applied {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.c.Confirm(types.ConfirmOpts{
|
return self.c.Confirm(types.ConfirmOpts{
|
||||||
@ -278,27 +290,15 @@ func (self *LocalCommitsController) squashDown(commit *models.Commit) error {
|
|||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(gocui.Task) error {
|
return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func(gocui.Task) error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.SquashCommitDown)
|
self.c.LogAction(self.c.Tr.Actions.SquashCommitDown)
|
||||||
return self.interactiveRebase(todo.Squash)
|
return self.interactiveRebase(todo.Squash, startIdx, endIdx)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) getDisabledReasonForSquashDown(commit *models.Commit) *types.DisabledReason {
|
func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
if self.context().GetSelectedLineIdx() >= len(self.c.Model().Commits)-1 {
|
if self.isRebasing() {
|
||||||
return &types.DisabledReason{Text: self.c.Tr.CannotSquashOrFixupFirstCommit}
|
return self.updateTodos(todo.Fixup, selectedCommits)
|
||||||
}
|
|
||||||
|
|
||||||
return self.rebaseCommandEnabled(todo.Squash)(commit)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *LocalCommitsController) fixup(commit *models.Commit) error {
|
|
||||||
applied, err := self.handleMidRebaseCommand(todo.Fixup, commit)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if applied {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.c.Confirm(types.ConfirmOpts{
|
return self.c.Confirm(types.ConfirmOpts{
|
||||||
@ -307,29 +307,13 @@ func (self *LocalCommitsController) fixup(commit *models.Commit) error {
|
|||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func(gocui.Task) error {
|
return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func(gocui.Task) error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.FixupCommit)
|
self.c.LogAction(self.c.Tr.Actions.FixupCommit)
|
||||||
return self.interactiveRebase(todo.Fixup)
|
return self.interactiveRebase(todo.Fixup, startIdx, endIdx)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) getDisabledReasonForFixup(commit *models.Commit) *types.DisabledReason {
|
|
||||||
if self.context().GetSelectedLineIdx() >= len(self.c.Model().Commits)-1 {
|
|
||||||
return &types.DisabledReason{Text: self.c.Tr.CannotSquashOrFixupFirstCommit}
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.rebaseCommandEnabled(todo.Squash)(commit)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *LocalCommitsController) reword(commit *models.Commit) error {
|
func (self *LocalCommitsController) reword(commit *models.Commit) error {
|
||||||
applied, err := self.handleMidRebaseCommand(todo.Reword, commit)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if applied {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
commitMessage, err := self.c.Git().Commit.GetCommitMessage(commit.Sha)
|
commitMessage, err := self.c.Git().Commit.GetCommitMessage(commit.Sha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return self.c.Error(err)
|
return self.c.Error(err)
|
||||||
@ -404,14 +388,6 @@ func (self *LocalCommitsController) doRewordEditor() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) rewordEditor(commit *models.Commit) error {
|
func (self *LocalCommitsController) rewordEditor(commit *models.Commit) error {
|
||||||
midRebase, err := self.handleMidRebaseCommand(todo.Reword, commit)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if midRebase {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.c.UserConfig.Gui.SkipRewordInEditorWarning {
|
if self.c.UserConfig.Gui.SkipRewordInEditorWarning {
|
||||||
return self.doRewordEditor()
|
return self.doRewordEditor()
|
||||||
} else {
|
} else {
|
||||||
@ -423,37 +399,37 @@ func (self *LocalCommitsController) rewordEditor(commit *models.Commit) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) drop(commit *models.Commit) error {
|
func (self *LocalCommitsController) drop(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
applied, err := self.handleMidRebaseCommand(todo.Drop, commit)
|
if self.isRebasing() {
|
||||||
if err != nil {
|
return self.updateTodos(todo.Drop, selectedCommits)
|
||||||
return err
|
|
||||||
}
|
|
||||||
if applied {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.c.Confirm(types.ConfirmOpts{
|
return self.c.Confirm(types.ConfirmOpts{
|
||||||
Title: self.c.Tr.DeleteCommitTitle,
|
Title: self.c.Tr.DropCommitTitle,
|
||||||
Prompt: self.c.Tr.DeleteCommitPrompt,
|
Prompt: self.c.Tr.DropCommitPrompt,
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(gocui.Task) error {
|
return self.c.WithWaitingStatus(self.c.Tr.DroppingStatus, func(gocui.Task) error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.DropCommit)
|
self.c.LogAction(self.c.Tr.Actions.DropCommit)
|
||||||
return self.interactiveRebase(todo.Drop)
|
return self.interactiveRebase(todo.Drop, startIdx, endIdx)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) edit(commit *models.Commit) error {
|
func (self *LocalCommitsController) edit(selectedCommits []*models.Commit) error {
|
||||||
applied, err := self.handleMidRebaseCommand(todo.Edit, commit)
|
if self.isRebasing() {
|
||||||
if err != nil {
|
return self.updateTodos(todo.Edit, selectedCommits)
|
||||||
return err
|
|
||||||
}
|
|
||||||
if applied {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.startInteractiveRebaseWithEdit(commit, commit)
|
// TODO: support range select here (start a rebase and set the selected commits
|
||||||
|
// to 'edit' in the todo file)
|
||||||
|
if len(selectedCommits) > 1 {
|
||||||
|
return self.c.ErrorMsg(self.c.Tr.RangeSelectNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedCommit := selectedCommits[0]
|
||||||
|
|
||||||
|
return self.startInteractiveRebaseWithEdit(selectedCommit, selectedCommit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) quickStartInteractiveRebase(selectedCommit *models.Commit) error {
|
func (self *LocalCommitsController) quickStartInteractiveRebase(selectedCommit *models.Commit) error {
|
||||||
@ -504,13 +480,9 @@ func (self *LocalCommitsController) findCommitForQuickStartInteractiveRebase() (
|
|||||||
return commit, nil
|
return commit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) pick(commit *models.Commit) error {
|
func (self *LocalCommitsController) pick(selectedCommits []*models.Commit) error {
|
||||||
applied, err := self.handleMidRebaseCommand(todo.Pick, commit)
|
if self.isRebasing() {
|
||||||
if err != nil {
|
return self.updateTodos(todo.Pick, selectedCommits)
|
||||||
return err
|
|
||||||
}
|
|
||||||
if applied {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this point we aren't actually rebasing so we will interpret this as an
|
// at this point we aren't actually rebasing so we will interpret this as an
|
||||||
@ -518,159 +490,93 @@ func (self *LocalCommitsController) pick(commit *models.Commit) error {
|
|||||||
return self.pullFiles()
|
return self.pullFiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) interactiveRebase(action todo.TodoCommand) error {
|
func (self *LocalCommitsController) interactiveRebase(action todo.TodoCommand, startIdx int, endIdx int) error {
|
||||||
err := self.c.Git().Rebase.InteractiveRebase(self.c.Model().Commits, self.context().GetSelectedLineIdx(), action)
|
// When performing an action that will remove the selected commits, we need to select the
|
||||||
|
// next commit down (which will end up at the start index after the action is performed)
|
||||||
|
if action == todo.Drop || action == todo.Fixup || action == todo.Squash {
|
||||||
|
self.context().SetSelection(startIdx)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := self.c.Git().Rebase.InteractiveRebase(self.c.Model().Commits, startIdx, endIdx, action)
|
||||||
|
|
||||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleMidRebaseCommand sees if the selected commit is in fact a rebasing
|
// updateTodos sees if the selected commit is in fact a rebasing
|
||||||
// commit meaning you are trying to edit the todo file rather than actually
|
// commit meaning you are trying to edit the todo file rather than actually
|
||||||
// begin a rebase. It then updates the todo file with that action
|
// begin a rebase. It then updates the todo file with that action
|
||||||
func (self *LocalCommitsController) handleMidRebaseCommand(action todo.TodoCommand, commit *models.Commit) (bool, error) {
|
func (self *LocalCommitsController) updateTodos(action todo.TodoCommand, selectedCommits []*models.Commit) error {
|
||||||
if !commit.IsTODO() {
|
if err := self.c.Git().Rebase.EditRebaseTodo(selectedCommits, action); err != nil {
|
||||||
return false, nil
|
return self.c.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.c.LogAction("Update rebase TODO")
|
return self.c.Refresh(types.RefreshOptions{
|
||||||
|
|
||||||
msg := utils.ResolvePlaceholderString(
|
|
||||||
self.c.Tr.Log.HandleMidRebaseCommand,
|
|
||||||
map[string]string{
|
|
||||||
"shortSha": commit.ShortSha(),
|
|
||||||
"action": action.String(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.c.LogCommand(msg, false)
|
|
||||||
|
|
||||||
if err := self.c.Git().Rebase.EditRebaseTodo(commit, action); err != nil {
|
|
||||||
return false, self.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, self.c.Refresh(types.RefreshOptions{
|
|
||||||
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
|
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) rebaseCommandEnabled(action todo.TodoCommand) func(*models.Commit) *types.DisabledReason {
|
func (self *LocalCommitsController) rewordEnabled(commit *models.Commit) *types.DisabledReason {
|
||||||
return func(commit *models.Commit) *types.DisabledReason {
|
// for now we do not support setting 'reword' on TODO commits because it requires an editor
|
||||||
if commit.Action == models.ActionConflict {
|
// and that means we either unconditionally wait around for the subprocess to ask for
|
||||||
return &types.DisabledReason{Text: self.c.Tr.ChangingThisActionIsNotAllowed}
|
// our input or we set a lazygit client as the EDITOR env variable and have it
|
||||||
}
|
// request us to edit the commit message when prompted.
|
||||||
|
if commit.IsTODO() {
|
||||||
if !commit.IsTODO() {
|
return &types.DisabledReason{Text: self.c.Tr.RewordNotSupported}
|
||||||
if self.c.Model().WorkingTreeStateAtLastCommitRefresh != enums.REBASE_MODE_NONE {
|
|
||||||
// If we are in a rebase, the only action that is allowed for
|
|
||||||
// non-todo commits is rewording the current head commit
|
|
||||||
if !(action == todo.Reword && self.isHeadCommit()) {
|
|
||||||
return &types.DisabledReason{Text: self.c.Tr.AlreadyRebasing}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// for now we do not support setting 'reword' because it requires an editor
|
|
||||||
// and that means we either unconditionally wait around for the subprocess to ask for
|
|
||||||
// our input or we set a lazygit client as the EDITOR env variable and have it
|
|
||||||
// request us to edit the commit message when prompted.
|
|
||||||
if action == todo.Reword {
|
|
||||||
return &types.DisabledReason{Text: self.c.Tr.RewordNotSupported}
|
|
||||||
}
|
|
||||||
|
|
||||||
if allowed := isChangeOfRebaseTodoAllowed(action); !allowed {
|
|
||||||
return &types.DisabledReason{Text: self.c.Tr.ChangingThisActionIsNotAllowed}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we are in a rebase, the only action that is allowed for
|
||||||
|
// non-todo commits is rewording the current head commit
|
||||||
|
if self.isRebasing() && !self.isHeadCommit() {
|
||||||
|
return &types.DisabledReason{Text: self.c.Tr.AlreadyRebasing}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) moveDown(commit *models.Commit) error {
|
func (self *LocalCommitsController) isRebasing() bool {
|
||||||
index := self.context().GetSelectedLineIdx()
|
return self.c.Model().WorkingTreeStateAtLastCommitRefresh != enums.REBASE_MODE_NONE
|
||||||
commits := self.c.Model().Commits
|
}
|
||||||
|
|
||||||
// can't move past the initial commit
|
func (self *LocalCommitsController) moveDown(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
if index >= len(commits)-1 {
|
if self.isRebasing() {
|
||||||
return nil
|
if err := self.c.Git().Rebase.MoveTodosDown(selectedCommits); err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
if commit.IsTODO() {
|
|
||||||
if !commits[index+1].IsTODO() || commits[index+1].Action == models.ActionConflict {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// logging directly here because MoveTodoDown doesn't have enough information
|
|
||||||
// to provide a useful log
|
|
||||||
self.c.LogAction(self.c.Tr.Actions.MoveCommitDown)
|
|
||||||
|
|
||||||
msg := utils.ResolvePlaceholderString(
|
|
||||||
self.c.Tr.Log.MovingCommitDown,
|
|
||||||
map[string]string{
|
|
||||||
"shortSha": commit.ShortSha(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.c.LogCommand(msg, false)
|
|
||||||
|
|
||||||
if err := self.c.Git().Rebase.MoveTodoDown(commit); err != nil {
|
|
||||||
return self.c.Error(err)
|
return self.c.Error(err)
|
||||||
}
|
}
|
||||||
self.context().MoveSelectedLine(1)
|
self.context().MoveSelection(1)
|
||||||
|
|
||||||
return self.c.Refresh(types.RefreshOptions{
|
return self.c.Refresh(types.RefreshOptions{
|
||||||
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
|
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
|
|
||||||
return self.c.ErrorMsg(self.c.Tr.AlreadyRebasing)
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.c.WithWaitingStatusSync(self.c.Tr.MovingStatus, func() error {
|
return self.c.WithWaitingStatusSync(self.c.Tr.MovingStatus, func() error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.MoveCommitDown)
|
self.c.LogAction(self.c.Tr.Actions.MoveCommitDown)
|
||||||
err := self.c.Git().Rebase.MoveCommitDown(self.c.Model().Commits, index)
|
err := self.c.Git().Rebase.MoveCommitsDown(self.c.Model().Commits, startIdx, endIdx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
self.context().MoveSelectedLine(1)
|
self.context().MoveSelection(1)
|
||||||
}
|
}
|
||||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
|
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
|
||||||
err, types.RefreshOptions{Mode: types.SYNC})
|
err, types.RefreshOptions{Mode: types.SYNC})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) moveUp(commit *models.Commit) error {
|
func (self *LocalCommitsController) moveUp(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
index := self.context().GetSelectedLineIdx()
|
if self.isRebasing() {
|
||||||
if index == 0 {
|
if err := self.c.Git().Rebase.MoveTodosUp(selectedCommits); err != nil {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if commit.IsTODO() {
|
|
||||||
// logging directly here because MoveTodoDown doesn't have enough information
|
|
||||||
// to provide a useful log
|
|
||||||
self.c.LogAction(self.c.Tr.Actions.MoveCommitUp)
|
|
||||||
msg := utils.ResolvePlaceholderString(
|
|
||||||
self.c.Tr.Log.MovingCommitUp,
|
|
||||||
map[string]string{
|
|
||||||
"shortSha": commit.ShortSha(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.c.LogCommand(msg, false)
|
|
||||||
|
|
||||||
if err := self.c.Git().Rebase.MoveTodoUp(self.c.Model().Commits[index]); err != nil {
|
|
||||||
return self.c.Error(err)
|
return self.c.Error(err)
|
||||||
}
|
}
|
||||||
self.context().MoveSelectedLine(-1)
|
self.context().MoveSelection(-1)
|
||||||
|
|
||||||
return self.c.Refresh(types.RefreshOptions{
|
return self.c.Refresh(types.RefreshOptions{
|
||||||
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
|
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
|
|
||||||
return self.c.ErrorMsg(self.c.Tr.AlreadyRebasing)
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.c.WithWaitingStatusSync(self.c.Tr.MovingStatus, func() error {
|
return self.c.WithWaitingStatusSync(self.c.Tr.MovingStatus, func() error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.MoveCommitUp)
|
self.c.LogAction(self.c.Tr.Actions.MoveCommitUp)
|
||||||
err := self.c.Git().Rebase.MoveCommitUp(self.c.Model().Commits, index)
|
err := self.c.Git().Rebase.MoveCommitsUp(self.c.Model().Commits, startIdx, endIdx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
self.context().MoveSelectedLine(-1)
|
self.context().MoveSelection(-1)
|
||||||
}
|
}
|
||||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
|
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
|
||||||
err, types.RefreshOptions{Mode: types.SYNC})
|
err, types.RefreshOptions{Mode: types.SYNC})
|
||||||
@ -693,10 +599,6 @@ func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
|
|
||||||
return self.c.ErrorMsg(self.c.Tr.AlreadyRebasing)
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.c.Confirm(types.ConfirmOpts{
|
return self.c.Confirm(types.ConfirmOpts{
|
||||||
Title: self.c.Tr.AmendCommitTitle,
|
Title: self.c.Tr.AmendCommitTitle,
|
||||||
Prompt: self.c.Tr.AmendCommitPrompt,
|
Prompt: self.c.Tr.AmendCommitPrompt,
|
||||||
@ -713,7 +615,7 @@ func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) canAmend(commit *models.Commit) *types.DisabledReason {
|
func (self *LocalCommitsController) canAmend(commit *models.Commit) *types.DisabledReason {
|
||||||
if !self.isHeadCommit() && self.c.Model().WorkingTreeStateAtLastCommitRefresh != enums.REBASE_MODE_NONE {
|
if !self.isHeadCommit() && self.isRebasing() {
|
||||||
return &types.DisabledReason{Text: self.c.Tr.AlreadyRebasing}
|
return &types.DisabledReason{Text: self.c.Tr.AlreadyRebasing}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -721,10 +623,6 @@ func (self *LocalCommitsController) canAmend(commit *models.Commit) *types.Disab
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) amendAttribute(commit *models.Commit) error {
|
func (self *LocalCommitsController) amendAttribute(commit *models.Commit) error {
|
||||||
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE && !self.isHeadCommit() {
|
|
||||||
return self.c.ErrorMsg(self.c.Tr.AlreadyRebasing)
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.c.Menu(types.CreateMenuOptions{
|
return self.c.Menu(types.CreateMenuOptions{
|
||||||
Title: "Amend commit attribute",
|
Title: "Amend commit attribute",
|
||||||
Items: []*types.MenuItem{
|
Items: []*types.MenuItem{
|
||||||
@ -846,7 +744,7 @@ func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) afterRevertCommit() error {
|
func (self *LocalCommitsController) afterRevertCommit() error {
|
||||||
self.context().MoveSelectedLine(1)
|
self.context().MoveSelection(1)
|
||||||
return self.c.Refresh(types.RefreshOptions{
|
return self.c.Refresh(types.RefreshOptions{
|
||||||
Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS, types.BRANCHES},
|
Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS, types.BRANCHES},
|
||||||
})
|
})
|
||||||
@ -895,24 +793,6 @@ func (self *LocalCommitsController) squashAllAboveFixupCommits(commit *models.Co
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// For getting disabled reason
|
|
||||||
func (self *LocalCommitsController) notMidRebase() *types.DisabledReason {
|
|
||||||
if self.c.Model().WorkingTreeStateAtLastCommitRefresh != enums.REBASE_MODE_NONE {
|
|
||||||
return &types.DisabledReason{Text: self.c.Tr.AlreadyRebasing}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// For getting disabled reason
|
|
||||||
func (self *LocalCommitsController) canFindCommitForQuickStart() *types.DisabledReason {
|
|
||||||
if _, err := self.findCommitForQuickStartInteractiveRebase(); err != nil {
|
|
||||||
return &types.DisabledReason{Text: err.Error(), ShowErrorInPanel: true}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *LocalCommitsController) createTag(commit *models.Commit) error {
|
func (self *LocalCommitsController) createTag(commit *models.Commit) error {
|
||||||
return self.c.Helpers().Tags.OpenCreateTagPrompt(commit.Sha, func() {})
|
return self.c.Helpers().Tags.OpenCreateTagPrompt(commit.Sha, func() {})
|
||||||
}
|
}
|
||||||
@ -1079,15 +959,88 @@ func (self *LocalCommitsController) isHeadCommit() bool {
|
|||||||
return models.IsHeadCommit(self.c.Model().Commits, self.context().GetSelectedLineIdx())
|
return models.IsHeadCommit(self.c.Model().Commits, self.context().GetSelectedLineIdx())
|
||||||
}
|
}
|
||||||
|
|
||||||
func isChangeOfRebaseTodoAllowed(action todo.TodoCommand) bool {
|
func (self *LocalCommitsController) notMidRebase(message string) func() *types.DisabledReason {
|
||||||
allowedActions := []todo.TodoCommand{
|
return func() *types.DisabledReason {
|
||||||
todo.Pick,
|
if self.isRebasing() {
|
||||||
todo.Drop,
|
return &types.DisabledReason{Text: message}
|
||||||
todo.Edit,
|
}
|
||||||
todo.Fixup,
|
|
||||||
todo.Squash,
|
return nil
|
||||||
todo.Reword,
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) canFindCommitForQuickStart() *types.DisabledReason {
|
||||||
|
if _, err := self.findCommitForQuickStartInteractiveRebase(); err != nil {
|
||||||
|
return &types.DisabledReason{Text: err.Error(), ShowErrorInPanel: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lo.Contains(allowedActions, action)
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) canSquashOrFixup(_selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
|
||||||
|
if endIdx >= len(self.c.Model().Commits)-1 {
|
||||||
|
return &types.DisabledReason{Text: self.c.Tr.CannotSquashOrFixupFirstCommit}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) canMoveDown(selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
|
||||||
|
if endIdx >= len(self.c.Model().Commits)-1 {
|
||||||
|
return &types.DisabledReason{Text: self.c.Tr.CannotMoveAnyFurther}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.isRebasing() {
|
||||||
|
commits := self.c.Model().Commits
|
||||||
|
|
||||||
|
if !commits[endIdx+1].IsTODO() || commits[endIdx+1].Action == models.ActionConflict {
|
||||||
|
return &types.DisabledReason{Text: self.c.Tr.CannotMoveAnyFurther}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) canMoveUp(selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
|
||||||
|
if startIdx == 0 {
|
||||||
|
return &types.DisabledReason{Text: self.c.Tr.CannotMoveAnyFurther}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.isRebasing() {
|
||||||
|
commits := self.c.Model().Commits
|
||||||
|
|
||||||
|
if !commits[startIdx-1].IsTODO() || commits[startIdx-1].Action == models.ActionConflict {
|
||||||
|
return &types.DisabledReason{Text: self.c.Tr.CannotMoveAnyFurther}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensures that if we are mid-rebase, we're only selecting valid commits (non-conflict TODO commits)
|
||||||
|
func (self *LocalCommitsController) midRebaseCommandEnabled(selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
|
||||||
|
if !self.isRebasing() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, commit := range selectedCommits {
|
||||||
|
if !commit.IsTODO() {
|
||||||
|
return &types.DisabledReason{Text: self.c.Tr.MustSelectTodoCommits}
|
||||||
|
}
|
||||||
|
|
||||||
|
if commit.Action == models.ActionConflict {
|
||||||
|
return &types.DisabledReason{Text: self.c.Tr.ChangingThisActionIsNotAllowed}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) pickEnabled(selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
|
||||||
|
if !self.isRebasing() {
|
||||||
|
// if not rebasing, we're going to do a pull so we don't care about the selection
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.midRebaseCommandEnabled(selectedCommits, startIdx, endIdx)
|
||||||
}
|
}
|
||||||
|
@ -217,8 +217,8 @@ func chineseTranslationSet() TranslationSet {
|
|||||||
ScrollDownMainPanel: "向下滚动主面板",
|
ScrollDownMainPanel: "向下滚动主面板",
|
||||||
AmendCommitTitle: "修改提交",
|
AmendCommitTitle: "修改提交",
|
||||||
AmendCommitPrompt: "您确定要使用暂存文件来修改此提交吗?",
|
AmendCommitPrompt: "您确定要使用暂存文件来修改此提交吗?",
|
||||||
DeleteCommitTitle: "删除提交",
|
DropCommitTitle: "删除提交",
|
||||||
DeleteCommitPrompt: "您确定要删除此提交吗?",
|
DropCommitPrompt: "您确定要删除此提交吗?",
|
||||||
PullingStatus: "正在拉取",
|
PullingStatus: "正在拉取",
|
||||||
PushingStatus: "正在推送",
|
PushingStatus: "正在推送",
|
||||||
FetchingStatus: "正在抓取",
|
FetchingStatus: "正在抓取",
|
||||||
|
@ -181,8 +181,8 @@ func dutchTranslationSet() TranslationSet {
|
|||||||
ScrollDownMainPanel: "Scroll naar beneden vanaf hoofdpaneel",
|
ScrollDownMainPanel: "Scroll naar beneden vanaf hoofdpaneel",
|
||||||
AmendCommitTitle: "Commit wijzigen",
|
AmendCommitTitle: "Commit wijzigen",
|
||||||
AmendCommitPrompt: "Weet je zeker dat je deze commit wil wijzigen met de vorige staged bestanden?",
|
AmendCommitPrompt: "Weet je zeker dat je deze commit wil wijzigen met de vorige staged bestanden?",
|
||||||
DeleteCommitTitle: "Verwijder commit",
|
DropCommitTitle: "Verwijder commit",
|
||||||
DeleteCommitPrompt: "Weet je zeker dat je deze commit wil verwijderen?",
|
DropCommitPrompt: "Weet je zeker dat je deze commit wil verwijderen?",
|
||||||
PullingStatus: "Pullen",
|
PullingStatus: "Pullen",
|
||||||
PushingStatus: "Pushen",
|
PushingStatus: "Pushen",
|
||||||
FetchingStatus: "Fetchen",
|
FetchingStatus: "Fetchen",
|
||||||
|
@ -119,6 +119,7 @@ type TranslationSet struct {
|
|||||||
DeleteCommit string
|
DeleteCommit string
|
||||||
MoveDownCommit string
|
MoveDownCommit string
|
||||||
MoveUpCommit string
|
MoveUpCommit string
|
||||||
|
CannotMoveAnyFurther string
|
||||||
EditCommit string
|
EditCommit string
|
||||||
AmendToCommit string
|
AmendToCommit string
|
||||||
ResetAuthor string
|
ResetAuthor string
|
||||||
@ -239,6 +240,7 @@ type TranslationSet struct {
|
|||||||
SimpleRebase string
|
SimpleRebase string
|
||||||
InteractiveRebase string
|
InteractiveRebase string
|
||||||
InteractiveRebaseTooltip string
|
InteractiveRebaseTooltip string
|
||||||
|
MustSelectTodoCommits string
|
||||||
ConfirmMerge string
|
ConfirmMerge string
|
||||||
FwdNoUpstream string
|
FwdNoUpstream string
|
||||||
FwdNoLocalUpstream string
|
FwdNoLocalUpstream string
|
||||||
@ -270,14 +272,15 @@ type TranslationSet struct {
|
|||||||
ScrollDownMainPanel string
|
ScrollDownMainPanel string
|
||||||
AmendCommitTitle string
|
AmendCommitTitle string
|
||||||
AmendCommitPrompt string
|
AmendCommitPrompt string
|
||||||
DeleteCommitTitle string
|
DropCommitTitle string
|
||||||
DeleteCommitPrompt string
|
DropCommitPrompt string
|
||||||
PullingStatus string
|
PullingStatus string
|
||||||
PushingStatus string
|
PushingStatus string
|
||||||
FetchingStatus string
|
FetchingStatus string
|
||||||
SquashingStatus string
|
SquashingStatus string
|
||||||
FixingStatus string
|
FixingStatus string
|
||||||
DeletingStatus string
|
DeletingStatus string
|
||||||
|
DroppingStatus string
|
||||||
MovingStatus string
|
MovingStatus string
|
||||||
RebasingStatus string
|
RebasingStatus string
|
||||||
MergingStatus string
|
MergingStatus string
|
||||||
@ -686,8 +689,6 @@ type Log struct {
|
|||||||
CherryPickCommits string
|
CherryPickCommits string
|
||||||
HandleUndo string
|
HandleUndo string
|
||||||
HandleMidRebaseCommand string
|
HandleMidRebaseCommand string
|
||||||
MovingCommitUp string
|
|
||||||
MovingCommitDown string
|
|
||||||
RemoveFile string
|
RemoveFile string
|
||||||
CopyToClipboard string
|
CopyToClipboard string
|
||||||
Remove string
|
Remove string
|
||||||
@ -945,8 +946,8 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
UpdateRefHere: "Update branch '{{.ref}}' here",
|
UpdateRefHere: "Update branch '{{.ref}}' here",
|
||||||
CannotSquashOrFixupFirstCommit: "There's no commit below to squash into",
|
CannotSquashOrFixupFirstCommit: "There's no commit below to squash into",
|
||||||
Fixup: "Fixup",
|
Fixup: "Fixup",
|
||||||
SureFixupThisCommit: "Are you sure you want to 'fixup' this commit? It will be merged into the commit below",
|
SureFixupThisCommit: "Are you sure you want to 'fixup' the selected commit(s) into the commit below?",
|
||||||
SureSquashThisCommit: "Are you sure you want to squash this commit into the commit below?",
|
SureSquashThisCommit: "Are you sure you want to squash the selected commit(s) into the commit below?",
|
||||||
Squash: "Squash",
|
Squash: "Squash",
|
||||||
PickCommit: "Pick commit (when mid-rebase)",
|
PickCommit: "Pick commit (when mid-rebase)",
|
||||||
RevertCommit: "Revert commit",
|
RevertCommit: "Revert commit",
|
||||||
@ -954,6 +955,7 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
DeleteCommit: "Delete commit",
|
DeleteCommit: "Delete commit",
|
||||||
MoveDownCommit: "Move commit down one",
|
MoveDownCommit: "Move commit down one",
|
||||||
MoveUpCommit: "Move commit up one",
|
MoveUpCommit: "Move commit up one",
|
||||||
|
CannotMoveAnyFurther: "Cannot move any further",
|
||||||
EditCommit: "Edit commit",
|
EditCommit: "Edit commit",
|
||||||
AmendToCommit: "Amend commit with staged changes",
|
AmendToCommit: "Amend commit with staged changes",
|
||||||
ResetAuthor: "Reset author",
|
ResetAuthor: "Reset author",
|
||||||
@ -1079,6 +1081,7 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
SimpleRebase: "Simple rebase",
|
SimpleRebase: "Simple rebase",
|
||||||
InteractiveRebase: "Interactive rebase",
|
InteractiveRebase: "Interactive rebase",
|
||||||
InteractiveRebaseTooltip: "Begin an interactive rebase with a break at the start, so you can update the TODO commits before continuing",
|
InteractiveRebaseTooltip: "Begin an interactive rebase with a break at the start, so you can update the TODO commits before continuing",
|
||||||
|
MustSelectTodoCommits: "When rebasing, this action only works on a selection of TODO commits.",
|
||||||
ConfirmMerge: "Are you sure you want to merge '{{.selectedBranch}}' into '{{.checkedOutBranch}}'?",
|
ConfirmMerge: "Are you sure you want to merge '{{.selectedBranch}}' into '{{.checkedOutBranch}}'?",
|
||||||
FwdNoUpstream: "Cannot fast-forward a branch with no upstream",
|
FwdNoUpstream: "Cannot fast-forward a branch with no upstream",
|
||||||
FwdNoLocalUpstream: "Cannot fast-forward a branch whose remote is not registered locally",
|
FwdNoLocalUpstream: "Cannot fast-forward a branch whose remote is not registered locally",
|
||||||
@ -1110,14 +1113,15 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
ScrollDownMainPanel: "Scroll down main panel",
|
ScrollDownMainPanel: "Scroll down main panel",
|
||||||
AmendCommitTitle: "Amend commit",
|
AmendCommitTitle: "Amend commit",
|
||||||
AmendCommitPrompt: "Are you sure you want to amend this commit with your staged files?",
|
AmendCommitPrompt: "Are you sure you want to amend this commit with your staged files?",
|
||||||
DeleteCommitTitle: "Delete commit",
|
DropCommitTitle: "Drop commit",
|
||||||
DeleteCommitPrompt: "Are you sure you want to delete this commit?",
|
DropCommitPrompt: "Are you sure you want to drop the selected commit(s)?",
|
||||||
PullingStatus: "Pulling",
|
PullingStatus: "Pulling",
|
||||||
PushingStatus: "Pushing",
|
PushingStatus: "Pushing",
|
||||||
FetchingStatus: "Fetching",
|
FetchingStatus: "Fetching",
|
||||||
SquashingStatus: "Squashing",
|
SquashingStatus: "Squashing",
|
||||||
FixingStatus: "Fixing up",
|
FixingStatus: "Fixing up",
|
||||||
DeletingStatus: "Deleting",
|
DeletingStatus: "Deleting",
|
||||||
|
DroppingStatus: "Dropping",
|
||||||
MovingStatus: "Moving",
|
MovingStatus: "Moving",
|
||||||
RebasingStatus: "Rebasing",
|
RebasingStatus: "Rebasing",
|
||||||
MergingStatus: "Merging",
|
MergingStatus: "Merging",
|
||||||
@ -1626,8 +1630,6 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
CherryPickCommits: "Cherry-picking commits:\n'{{.commitLines}}'",
|
CherryPickCommits: "Cherry-picking commits:\n'{{.commitLines}}'",
|
||||||
HandleUndo: "Undoing last conflict resolution",
|
HandleUndo: "Undoing last conflict resolution",
|
||||||
HandleMidRebaseCommand: "Updating rebase action of commit {{.shortSha}} to '{{.action}}'",
|
HandleMidRebaseCommand: "Updating rebase action of commit {{.shortSha}} to '{{.action}}'",
|
||||||
MovingCommitUp: "Moving commit {{.shortSha}} up",
|
|
||||||
MovingCommitDown: "Moving commit {{.shortSha}} down",
|
|
||||||
RemoveFile: "Deleting path '{{.path}}'",
|
RemoveFile: "Deleting path '{{.path}}'",
|
||||||
CopyToClipboard: "Copying '{{.str}}' to clipboard",
|
CopyToClipboard: "Copying '{{.str}}' to clipboard",
|
||||||
Remove: "Removing '{{.filename}}'",
|
Remove: "Removing '{{.filename}}'",
|
||||||
|
@ -221,8 +221,8 @@ func japaneseTranslationSet() TranslationSet {
|
|||||||
ScrollDownMainPanel: "メインパネルを下にスクロール",
|
ScrollDownMainPanel: "メインパネルを下にスクロール",
|
||||||
AmendCommitTitle: "Amendコミット",
|
AmendCommitTitle: "Amendコミット",
|
||||||
AmendCommitPrompt: "ステージされたファイルで現在のコミットをamendします。よろしいですか?",
|
AmendCommitPrompt: "ステージされたファイルで現在のコミットをamendします。よろしいですか?",
|
||||||
DeleteCommitTitle: "コミットを削除",
|
DropCommitTitle: "コミットを削除",
|
||||||
DeleteCommitPrompt: "選択されたコミットを削除します。よろしいですか?",
|
DropCommitPrompt: "選択されたコミットを削除します。よろしいですか?",
|
||||||
PullingStatus: "Pull中",
|
PullingStatus: "Pull中",
|
||||||
PushingStatus: "Push中",
|
PushingStatus: "Push中",
|
||||||
FetchingStatus: "Fetch中",
|
FetchingStatus: "Fetch中",
|
||||||
|
@ -218,8 +218,8 @@ func koreanTranslationSet() TranslationSet {
|
|||||||
ScrollDownMainPanel: "메인 패널을 아래로로 스크롤",
|
ScrollDownMainPanel: "메인 패널을 아래로로 스크롤",
|
||||||
AmendCommitTitle: "Amend commit",
|
AmendCommitTitle: "Amend commit",
|
||||||
AmendCommitPrompt: "Are you sure you want to amend this commit with your staged files?",
|
AmendCommitPrompt: "Are you sure you want to amend this commit with your staged files?",
|
||||||
DeleteCommitTitle: "커밋 삭제",
|
DropCommitTitle: "커밋 삭제",
|
||||||
DeleteCommitPrompt: "정말로 선택한 커밋을 삭제하시겠습니까?",
|
DropCommitPrompt: "정말로 선택한 커밋을 삭제하시겠습니까?",
|
||||||
PullingStatus: "업데이트 중",
|
PullingStatus: "업데이트 중",
|
||||||
PushingStatus: "푸시 중",
|
PushingStatus: "푸시 중",
|
||||||
FetchingStatus: "패치 중",
|
FetchingStatus: "패치 중",
|
||||||
|
@ -147,8 +147,8 @@ func polishTranslationSet() TranslationSet {
|
|||||||
ScrollUp: "Przewiń w górę",
|
ScrollUp: "Przewiń w górę",
|
||||||
AmendCommitTitle: "Popraw commit",
|
AmendCommitTitle: "Popraw commit",
|
||||||
AmendCommitPrompt: "Czy na pewno chcesz poprawić ten commit plikami z poczekalni?",
|
AmendCommitPrompt: "Czy na pewno chcesz poprawić ten commit plikami z poczekalni?",
|
||||||
DeleteCommitTitle: "Usuń commit",
|
DropCommitTitle: "Usuń commit",
|
||||||
DeleteCommitPrompt: "Czy na pewno usunąć ten commit?",
|
DropCommitPrompt: "Czy na pewno usunąć ten commit?",
|
||||||
PullingStatus: "Pobieranie zmian",
|
PullingStatus: "Pobieranie zmian",
|
||||||
PushingStatus: "Wysyłanie zmian",
|
PushingStatus: "Wysyłanie zmian",
|
||||||
FetchingStatus: "Pobieram",
|
FetchingStatus: "Pobieram",
|
||||||
|
@ -262,8 +262,8 @@ func RussianTranslationSet() TranslationSet {
|
|||||||
ScrollDownMainPanel: "Прокрутить вниз главную панель",
|
ScrollDownMainPanel: "Прокрутить вниз главную панель",
|
||||||
AmendCommitTitle: "Править коммит (amend)",
|
AmendCommitTitle: "Править коммит (amend)",
|
||||||
AmendCommitPrompt: "Вы уверены, что хотите править этот коммит проиндексированными файлами?",
|
AmendCommitPrompt: "Вы уверены, что хотите править этот коммит проиндексированными файлами?",
|
||||||
DeleteCommitTitle: "Удалить коммит",
|
DropCommitTitle: "Удалить коммит",
|
||||||
DeleteCommitPrompt: "Вы уверены, что хотите удалить этот коммит?",
|
DropCommitPrompt: "Вы уверены, что хотите удалить этот коммит?",
|
||||||
PullingStatus: "Получение и слияние изменении",
|
PullingStatus: "Получение и слияние изменении",
|
||||||
PushingStatus: "Отправка изменении",
|
PushingStatus: "Отправка изменении",
|
||||||
FetchingStatus: "Получение изменении",
|
FetchingStatus: "Получение изменении",
|
||||||
|
@ -293,8 +293,8 @@ func traditionalChineseTranslationSet() TranslationSet {
|
|||||||
ScrollDownMainPanel: "向下捲動主面板",
|
ScrollDownMainPanel: "向下捲動主面板",
|
||||||
AmendCommitTitle: "修正提交",
|
AmendCommitTitle: "修正提交",
|
||||||
AmendCommitPrompt: "你確定要使用預存的檔案修正此提交嗎?",
|
AmendCommitPrompt: "你確定要使用預存的檔案修正此提交嗎?",
|
||||||
DeleteCommitTitle: "刪除提交",
|
DropCommitTitle: "刪除提交",
|
||||||
DeleteCommitPrompt: "你確定要刪除此提交嗎?",
|
DropCommitPrompt: "你確定要刪除此提交嗎?",
|
||||||
PullingStatus: "拉取",
|
PullingStatus: "拉取",
|
||||||
PushingStatus: "推送",
|
PushingStatus: "推送",
|
||||||
FetchingStatus: "擷取",
|
FetchingStatus: "擷取",
|
||||||
|
@ -22,8 +22,8 @@ var Undo = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
|
|
||||||
confirmCommitDrop := func() {
|
confirmCommitDrop := func() {
|
||||||
t.ExpectPopup().Confirmation().
|
t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Delete commit")).
|
Title(Equals("Drop commit")).
|
||||||
Content(Equals("Are you sure you want to delete this commit?")).
|
Content(Equals("Are you sure you want to drop the selected commit(s)?")).
|
||||||
Wait(500).
|
Wait(500).
|
||||||
Confirm()
|
Confirm()
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ var DropWithCustomCommentChar = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Press(keys.Universal.Remove).
|
Press(keys.Universal.Remove).
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectPopup().Confirmation().
|
t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Delete commit")).
|
Title(Equals("Drop commit")).
|
||||||
Content(Equals("Are you sure you want to delete this commit?")).
|
Content(Equals("Are you sure you want to drop the selected commit(s)?")).
|
||||||
Confirm()
|
Confirm()
|
||||||
}).
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
|
@ -29,6 +29,6 @@ var EditNonTodoCommitDuringRebase = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
NavigateToLine(Contains("commit 01")).
|
NavigateToLine(Contains("commit 01")).
|
||||||
Press(keys.Universal.Edit)
|
Press(keys.Universal.Edit)
|
||||||
|
|
||||||
t.ExpectToast(Contains("Can't perform this action during a rebase"))
|
t.ExpectToast(Contains("Disabled: When rebasing, this action only works on a selection of TODO commits."))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -39,6 +39,6 @@ var EditTheConflCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
NavigateToLine(Contains("<-- YOU ARE HERE --- commit three")).
|
NavigateToLine(Contains("<-- YOU ARE HERE --- commit three")).
|
||||||
Press(keys.Commits.RenameCommit)
|
Press(keys.Commits.RenameCommit)
|
||||||
|
|
||||||
t.ExpectToast(Contains("Changing this kind of rebase todo entry is not allowed"))
|
t.ExpectToast(Contains("Disabled: Rewording commits while interactively rebasing is not currently supported"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -29,7 +29,7 @@ var FixupSecondCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectPopup().Confirmation().
|
t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Fixup")).
|
Title(Equals("Fixup")).
|
||||||
Content(Equals("Are you sure you want to 'fixup' this commit? It will be merged into the commit below")).
|
Content(Equals("Are you sure you want to 'fixup' the selected commit(s) into the commit below?")).
|
||||||
Confirm()
|
Confirm()
|
||||||
}).
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
|
@ -0,0 +1,205 @@
|
|||||||
|
package interactive_rebase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var MidRebaseRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Do various things with range selection in the commits view when mid-rebase",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.
|
||||||
|
CreateNCommits(10)
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Commits().
|
||||||
|
Focus().
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 10").IsSelected(),
|
||||||
|
).
|
||||||
|
NavigateToLine(Contains("commit 07")).
|
||||||
|
Press(keys.Universal.RangeSelectDown).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 10"),
|
||||||
|
Contains("commit 09"),
|
||||||
|
Contains("commit 08"),
|
||||||
|
Contains("commit 07").IsSelected(),
|
||||||
|
Contains("commit 06").IsSelected(),
|
||||||
|
Contains("commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
// Verify we can't perform an edit on multiple commits (it's not supported
|
||||||
|
// yet)
|
||||||
|
Press(keys.Universal.Edit).
|
||||||
|
Tap(func() {
|
||||||
|
// This ought to be a toast but I'm too lazy to implement that right now.
|
||||||
|
t.ExpectPopup().Alert().
|
||||||
|
Title(Equals("Error")).
|
||||||
|
Content(Contains("Action does not support range selection, please select a single item")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
NavigateToLine(Contains("commit 05")).
|
||||||
|
// Start a rebase
|
||||||
|
Press(keys.Universal.Edit).
|
||||||
|
TopLines(
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("pick").Contains("commit 07"),
|
||||||
|
Contains("pick").Contains("commit 06"),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05").IsSelected(),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
SelectPreviousItem().
|
||||||
|
// perform various actions on a range of commits
|
||||||
|
Press(keys.Universal.RangeSelectUp).
|
||||||
|
TopLines(
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("pick").Contains("commit 07").IsSelected(),
|
||||||
|
Contains("pick").Contains("commit 06").IsSelected(),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MarkCommitAsFixup).
|
||||||
|
TopLines(
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("fixup").Contains("commit 07").IsSelected(),
|
||||||
|
Contains("fixup").Contains("commit 06").IsSelected(),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.PickCommit).
|
||||||
|
TopLines(
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("pick").Contains("commit 07").IsSelected(),
|
||||||
|
Contains("pick").Contains("commit 06").IsSelected(),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.Edit).
|
||||||
|
TopLines(
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("edit").Contains("commit 07").IsSelected(),
|
||||||
|
Contains("edit").Contains("commit 06").IsSelected(),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.SquashDown).
|
||||||
|
TopLines(
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("squash").Contains("commit 07").IsSelected(),
|
||||||
|
Contains("squash").Contains("commit 06").IsSelected(),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MoveDownCommit).
|
||||||
|
TopLines(
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("squash").Contains("commit 07").IsSelected(),
|
||||||
|
Contains("squash").Contains("commit 06").IsSelected(),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectToast(Contains("Disabled: Cannot move any further"))
|
||||||
|
}).
|
||||||
|
Press(keys.Commits.MoveUpCommit).
|
||||||
|
TopLines(
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("squash").Contains("commit 07").IsSelected(),
|
||||||
|
Contains("squash").Contains("commit 06").IsSelected(),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MoveUpCommit).
|
||||||
|
TopLines(
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("squash").Contains("commit 07").IsSelected(),
|
||||||
|
Contains("squash").Contains("commit 06").IsSelected(),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MoveUpCommit).
|
||||||
|
TopLines(
|
||||||
|
Contains("squash").Contains("commit 07").IsSelected(),
|
||||||
|
Contains("squash").Contains("commit 06").IsSelected(),
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MoveUpCommit).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectToast(Contains("Disabled: Cannot move any further"))
|
||||||
|
}).
|
||||||
|
TopLines(
|
||||||
|
Contains("squash").Contains("commit 07").IsSelected(),
|
||||||
|
Contains("squash").Contains("commit 06").IsSelected(),
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08"),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
// Verify we can't perform an action on a range that includes both
|
||||||
|
// TODO and non-TODO commits
|
||||||
|
NavigateToLine(Contains("commit 08")).
|
||||||
|
Press(keys.Universal.RangeSelectDown).
|
||||||
|
TopLines(
|
||||||
|
Contains("squash").Contains("commit 07"),
|
||||||
|
Contains("squash").Contains("commit 06"),
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08").IsSelected(),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05").IsSelected(),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MarkCommitAsFixup).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectToast(Contains("Disabled: When rebasing, this action only works on a selection of TODO commits."))
|
||||||
|
}).
|
||||||
|
TopLines(
|
||||||
|
Contains("squash").Contains("commit 07"),
|
||||||
|
Contains("squash").Contains("commit 06"),
|
||||||
|
Contains("pick").Contains("commit 10"),
|
||||||
|
Contains("pick").Contains("commit 09"),
|
||||||
|
Contains("pick").Contains("commit 08").IsSelected(),
|
||||||
|
Contains("<-- YOU ARE HERE --- commit 05").IsSelected(),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
// continue the rebase
|
||||||
|
Tap(func() {
|
||||||
|
t.Common().ContinueRebase()
|
||||||
|
}).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 10"),
|
||||||
|
Contains("commit 09"),
|
||||||
|
Contains("commit 08"),
|
||||||
|
Contains("commit 05"),
|
||||||
|
// selected indexes are retained, though we may want to clear it
|
||||||
|
// in future (not sure what the best behaviour is right now)
|
||||||
|
Contains("commit 04").IsSelected(),
|
||||||
|
Contains("commit 03").IsSelected(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
@ -45,6 +45,9 @@ var Move = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
).
|
).
|
||||||
// assert nothing happens upon trying to move beyond the last commit
|
// assert nothing happens upon trying to move beyond the last commit
|
||||||
Press(keys.Commits.MoveDownCommit).
|
Press(keys.Commits.MoveDownCommit).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectToast(Contains("Disabled: Cannot move any further"))
|
||||||
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
Contains("commit 03"),
|
Contains("commit 03"),
|
||||||
Contains("commit 02"),
|
Contains("commit 02"),
|
||||||
@ -74,6 +77,9 @@ var Move = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
).
|
).
|
||||||
// assert nothing happens upon trying to move beyond the first commit
|
// assert nothing happens upon trying to move beyond the first commit
|
||||||
Press(keys.Commits.MoveUpCommit).
|
Press(keys.Commits.MoveUpCommit).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectToast(Contains("Disabled: Cannot move any further"))
|
||||||
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
Contains("commit 04").IsSelected(),
|
Contains("commit 04").IsSelected(),
|
||||||
Contains("commit 03"),
|
Contains("commit 03"),
|
||||||
|
@ -45,8 +45,11 @@ var MoveInRebase = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Contains("commit 03"),
|
Contains("commit 03"),
|
||||||
Contains("YOU ARE HERE").Contains("commit 01"),
|
Contains("YOU ARE HERE").Contains("commit 01"),
|
||||||
).
|
).
|
||||||
Press(keys.Commits.MoveUpCommit).
|
|
||||||
// assert we can't move past the top
|
// assert we can't move past the top
|
||||||
|
Press(keys.Commits.MoveUpCommit).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectToast(Contains("Disabled: Cannot move any further"))
|
||||||
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
Contains("commit 02").IsSelected(),
|
Contains("commit 02").IsSelected(),
|
||||||
Contains("commit 04"),
|
Contains("commit 04"),
|
||||||
@ -69,6 +72,9 @@ var MoveInRebase = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
).
|
).
|
||||||
// assert we can't move past the bottom
|
// assert we can't move past the bottom
|
||||||
Press(keys.Commits.MoveDownCommit).
|
Press(keys.Commits.MoveDownCommit).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectToast(Contains("Disabled: Cannot move any further"))
|
||||||
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
Contains("commit 04"),
|
Contains("commit 04"),
|
||||||
Contains("commit 03"),
|
Contains("commit 03"),
|
||||||
|
@ -0,0 +1,155 @@
|
|||||||
|
package interactive_rebase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var OutsideRebaseRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Do various things with range selection in the commits view when outside rebase",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.
|
||||||
|
CreateNCommits(10)
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Commits().
|
||||||
|
Focus().
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 10").IsSelected(),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.RangeSelectDown).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 10").IsSelected(),
|
||||||
|
Contains("commit 09").IsSelected(),
|
||||||
|
Contains("commit 08"),
|
||||||
|
).
|
||||||
|
// Drop commits
|
||||||
|
Press(keys.Universal.Remove).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().Confirmation().
|
||||||
|
Title(Equals("Drop commit")).
|
||||||
|
Content(Contains("Are you sure you want to drop the selected commit(s)?")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 08").IsSelected(),
|
||||||
|
Contains("commit 07"),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.RangeSelectDown).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 08").IsSelected(),
|
||||||
|
Contains("commit 07").IsSelected(),
|
||||||
|
Contains("commit 06"),
|
||||||
|
).
|
||||||
|
// Squash commits
|
||||||
|
Press(keys.Commits.SquashDown).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().Confirmation().
|
||||||
|
Title(Equals("Squash")).
|
||||||
|
Content(Contains("Are you sure you want to squash the selected commit(s) into the commit below?")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 06").IsSelected(),
|
||||||
|
Contains("commit 05"),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
// Verify commit messages are concatenated
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Main().
|
||||||
|
ContainsLines(
|
||||||
|
Contains("commit 06"),
|
||||||
|
AnyString(),
|
||||||
|
Contains("commit 07"),
|
||||||
|
AnyString(),
|
||||||
|
Contains("commit 08"),
|
||||||
|
)
|
||||||
|
}).
|
||||||
|
// Fixup commits
|
||||||
|
Press(keys.Universal.RangeSelectDown).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 06").IsSelected(),
|
||||||
|
Contains("commit 05").IsSelected(),
|
||||||
|
Contains("commit 04"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MarkCommitAsFixup).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().Confirmation().
|
||||||
|
Title(Equals("Fixup")).
|
||||||
|
Content(Contains("Are you sure you want to 'fixup' the selected commit(s) into the commit below?")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 04").IsSelected(),
|
||||||
|
Contains("commit 03"),
|
||||||
|
Contains("commit 02"),
|
||||||
|
).
|
||||||
|
// Verify commit messages are dropped
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Main().
|
||||||
|
Content(
|
||||||
|
Contains("commit 04").
|
||||||
|
DoesNotContain("commit 06").
|
||||||
|
DoesNotContain("commit 05"),
|
||||||
|
)
|
||||||
|
}).
|
||||||
|
Press(keys.Universal.RangeSelectDown).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 04").IsSelected(),
|
||||||
|
Contains("commit 03").IsSelected(),
|
||||||
|
Contains("commit 02"),
|
||||||
|
).
|
||||||
|
// Move commits
|
||||||
|
Press(keys.Commits.MoveDownCommit).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 02"),
|
||||||
|
Contains("commit 04").IsSelected(),
|
||||||
|
Contains("commit 03").IsSelected(),
|
||||||
|
Contains("commit 01"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MoveDownCommit).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 02"),
|
||||||
|
Contains("commit 01"),
|
||||||
|
Contains("commit 04").IsSelected(),
|
||||||
|
Contains("commit 03").IsSelected(),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MoveDownCommit).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 02"),
|
||||||
|
Contains("commit 01"),
|
||||||
|
Contains("commit 04").IsSelected(),
|
||||||
|
Contains("commit 03").IsSelected(),
|
||||||
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectToast(Contains("Disabled: Cannot move any further"))
|
||||||
|
}).
|
||||||
|
Press(keys.Commits.MoveUpCommit).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 02"),
|
||||||
|
Contains("commit 04").IsSelected(),
|
||||||
|
Contains("commit 03").IsSelected(),
|
||||||
|
Contains("commit 01"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MoveUpCommit).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 04").IsSelected(),
|
||||||
|
Contains("commit 03").IsSelected(),
|
||||||
|
Contains("commit 02"),
|
||||||
|
Contains("commit 01"),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.MoveUpCommit).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectToast(Contains("Disabled: Cannot move any further"))
|
||||||
|
}).
|
||||||
|
TopLines(
|
||||||
|
Contains("commit 04").IsSelected(),
|
||||||
|
Contains("commit 03").IsSelected(),
|
||||||
|
Contains("commit 02"),
|
||||||
|
Contains("commit 01"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
@ -27,7 +27,7 @@ var SquashDownSecondCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectPopup().Confirmation().
|
t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Squash")).
|
Title(Equals("Squash")).
|
||||||
Content(Equals("Are you sure you want to squash this commit into the commit below?")).
|
Content(Equals("Are you sure you want to squash the selected commit(s) into the commit below?")).
|
||||||
Confirm()
|
Confirm()
|
||||||
}).
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
|
@ -165,6 +165,7 @@ var tests = []*components.IntegrationTest{
|
|||||||
interactive_rebase.Move,
|
interactive_rebase.Move,
|
||||||
interactive_rebase.MoveInRebase,
|
interactive_rebase.MoveInRebase,
|
||||||
interactive_rebase.MoveWithCustomCommentChar,
|
interactive_rebase.MoveWithCustomCommentChar,
|
||||||
|
interactive_rebase.OutsideRebaseRangeSelect,
|
||||||
interactive_rebase.PickRescheduled,
|
interactive_rebase.PickRescheduled,
|
||||||
interactive_rebase.QuickStart,
|
interactive_rebase.QuickStart,
|
||||||
interactive_rebase.Rebase,
|
interactive_rebase.Rebase,
|
||||||
|
@ -24,8 +24,8 @@ var UndoCheckoutAndDrop = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
|
|
||||||
confirmCommitDrop := func() {
|
confirmCommitDrop := func() {
|
||||||
t.ExpectPopup().Confirmation().
|
t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Delete commit")).
|
Title(Equals("Drop commit")).
|
||||||
Content(Equals("Are you sure you want to delete this commit?")).
|
Content(Equals("Are you sure you want to drop the selected commit(s)?")).
|
||||||
Confirm()
|
Confirm()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ var UndoDrop = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
confirmCommitDrop := func() {
|
confirmCommitDrop := func() {
|
||||||
t.ExpectPopup().Confirmation().
|
t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Delete commit")).
|
Title(Equals("Drop commit")).
|
||||||
Content(Equals("Are you sure you want to delete this commit?")).
|
Content(Equals("Are you sure you want to drop the selected commit(s)?")).
|
||||||
Confirm()
|
Confirm()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,27 +9,46 @@ import (
|
|||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Read a git-rebase-todo file, change the action for the given sha to
|
type Todo struct {
|
||||||
// newAction, and write it back
|
Sha string
|
||||||
func EditRebaseTodo(filePath string, sha string, oldAction todo.TodoCommand, newAction todo.TodoCommand, commentChar byte) error {
|
Action todo.TodoCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
// In order to change a TODO in git-rebase-todo, we need to specify the old action,
|
||||||
|
// because sometimes the same sha appears multiple times in the file (e.g. in a pick
|
||||||
|
// and later in a merge)
|
||||||
|
type TodoChange struct {
|
||||||
|
Sha string
|
||||||
|
OldAction todo.TodoCommand
|
||||||
|
NewAction todo.TodoCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a git-rebase-todo file, change the actions for the given commits,
|
||||||
|
// and write it back
|
||||||
|
func EditRebaseTodo(filePath string, changes []TodoChange, commentChar byte) error {
|
||||||
todos, err := ReadRebaseTodoFile(filePath, commentChar)
|
todos, err := ReadRebaseTodoFile(filePath, commentChar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
matchCount := 0
|
||||||
for i := range todos {
|
for i := range todos {
|
||||||
t := &todos[i]
|
t := &todos[i]
|
||||||
// Comparing just the sha is not enough; we need to compare both the
|
// This is a nested loop, but it's ok because the number of todos should be small
|
||||||
// action and the sha, as the sha could appear multiple times (e.g. in a
|
for _, change := range changes {
|
||||||
// pick and later in a merge)
|
if t.Command == change.OldAction && equalShas(t.Commit, change.Sha) {
|
||||||
if t.Command == oldAction && equalShas(t.Commit, sha) {
|
matchCount++
|
||||||
t.Command = newAction
|
t.Command = change.NewAction
|
||||||
return WriteRebaseTodoFile(filePath, todos, commentChar)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should never get here
|
if matchCount < len(changes) {
|
||||||
return fmt.Errorf("Todo %s not found in git-rebase-todo", sha)
|
// Should never get here
|
||||||
|
return fmt.Errorf("Some todos not found in git-rebase-todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
return WriteRebaseTodoFile(filePath, todos, commentChar)
|
||||||
}
|
}
|
||||||
|
|
||||||
func equalShas(a, b string) bool {
|
func equalShas(a, b string) bool {
|
||||||
@ -73,24 +92,24 @@ func PrependStrToTodoFile(filePath string, linesToPrepend []byte) error {
|
|||||||
return os.WriteFile(filePath, linesToPrepend, 0o644)
|
return os.WriteFile(filePath, linesToPrepend, 0o644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MoveTodoDown(fileName string, sha string, action todo.TodoCommand, commentChar byte) error {
|
func MoveTodosDown(fileName string, todosToMove []Todo, commentChar byte) error {
|
||||||
todos, err := ReadRebaseTodoFile(fileName, commentChar)
|
todos, err := ReadRebaseTodoFile(fileName, commentChar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rearrangedTodos, err := moveTodoDown(todos, sha, action)
|
rearrangedTodos, err := moveTodosDown(todos, todosToMove)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return WriteRebaseTodoFile(fileName, rearrangedTodos, commentChar)
|
return WriteRebaseTodoFile(fileName, rearrangedTodos, commentChar)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MoveTodoUp(fileName string, sha string, action todo.TodoCommand, commentChar byte) error {
|
func MoveTodosUp(fileName string, todosToMove []Todo, commentChar byte) error {
|
||||||
todos, err := ReadRebaseTodoFile(fileName, commentChar)
|
todos, err := ReadRebaseTodoFile(fileName, commentChar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rearrangedTodos, err := moveTodoUp(todos, sha, action)
|
rearrangedTodos, err := moveTodosUp(todos, todosToMove)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -102,6 +121,11 @@ func moveTodoDown(todos []todo.Todo, sha string, action todo.TodoCommand) ([]tod
|
|||||||
return lo.Reverse(rearrangedTodos), err
|
return lo.Reverse(rearrangedTodos), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func moveTodosDown(todos []todo.Todo, todosToMove []Todo) ([]todo.Todo, error) {
|
||||||
|
rearrangedTodos, err := moveTodosUp(lo.Reverse(todos), lo.Reverse(todosToMove))
|
||||||
|
return lo.Reverse(rearrangedTodos), err
|
||||||
|
}
|
||||||
|
|
||||||
func moveTodoUp(todos []todo.Todo, sha string, action todo.TodoCommand) ([]todo.Todo, error) {
|
func moveTodoUp(todos []todo.Todo, sha string, action todo.TodoCommand) ([]todo.Todo, error) {
|
||||||
_, sourceIdx, ok := lo.FindIndexOf(todos, func(t todo.Todo) bool {
|
_, sourceIdx, ok := lo.FindIndexOf(todos, func(t todo.Todo) bool {
|
||||||
// Comparing just the sha is not enough; we need to compare both the
|
// Comparing just the sha is not enough; we need to compare both the
|
||||||
@ -134,6 +158,19 @@ func moveTodoUp(todos []todo.Todo, sha string, action todo.TodoCommand) ([]todo.
|
|||||||
return rearrangedTodos, nil
|
return rearrangedTodos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func moveTodosUp(todos []todo.Todo, todosToMove []Todo) ([]todo.Todo, error) {
|
||||||
|
for _, todoToMove := range todosToMove {
|
||||||
|
var newTodos []todo.Todo
|
||||||
|
newTodos, err := moveTodoUp(todos, todoToMove.Sha, todoToMove.Action)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
todos = newTodos
|
||||||
|
}
|
||||||
|
|
||||||
|
return todos, nil
|
||||||
|
}
|
||||||
|
|
||||||
func MoveFixupCommitDown(fileName string, originalSha string, fixupSha string, commentChar byte) error {
|
func MoveFixupCommitDown(fileName string, originalSha string, fixupSha string, commentChar byte) error {
|
||||||
todos, err := ReadRebaseTodoFile(fileName, commentChar)
|
todos, err := ReadRebaseTodoFile(fileName, commentChar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user