2018-12-08 16:54:54 +11:00
|
|
|
package gui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
2020-11-16 20:38:26 +11:00
|
|
|
|
2021-12-30 13:35:10 +11:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
2022-01-28 20:44:36 +11:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
2018-12-08 16:54:54 +11:00
|
|
|
)
|
|
|
|
|
2021-11-01 08:58:58 +11:00
|
|
|
type RebaseOption string
|
|
|
|
|
|
|
|
const (
|
|
|
|
REBASE_OPTION_CONTINUE = "continue"
|
|
|
|
REBASE_OPTION_ABORT = "abort"
|
|
|
|
REBASE_OPTION_SKIP = "skip"
|
|
|
|
)
|
|
|
|
|
2020-08-15 17:23:16 +10:00
|
|
|
func (gui *Gui) handleCreateRebaseOptionsMenu() error {
|
2021-11-01 08:58:58 +11:00
|
|
|
options := []string{REBASE_OPTION_CONTINUE, REBASE_OPTION_ABORT}
|
2018-12-08 16:54:54 +11:00
|
|
|
|
2022-01-16 14:46:53 +11:00
|
|
|
if gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
|
2021-11-01 08:58:58 +11:00
|
|
|
options = append(options, REBASE_OPTION_SKIP)
|
2018-12-08 16:54:54 +11:00
|
|
|
}
|
|
|
|
|
2022-01-29 19:09:20 +11:00
|
|
|
menuItems := make([]*types.MenuItem, len(options))
|
2020-02-14 23:29:41 +11:00
|
|
|
for i, option := range options {
|
2020-02-25 22:08:03 +11:00
|
|
|
// note to self. Never, EVER, close over loop variables in a function
|
2020-03-09 11:34:10 +11:00
|
|
|
option := option
|
2022-01-29 19:09:20 +11:00
|
|
|
menuItems[i] = &types.MenuItem{
|
2022-01-28 20:44:36 +11:00
|
|
|
DisplayString: option,
|
|
|
|
OnPress: func() error {
|
2020-03-09 11:34:10 +11:00
|
|
|
return gui.genericMergeCommand(option)
|
2020-02-14 23:29:41 +11:00
|
|
|
},
|
2019-11-10 16:20:35 +11:00
|
|
|
}
|
2018-12-08 16:54:54 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
var title string
|
2022-01-16 14:46:53 +11:00
|
|
|
if gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_MERGING {
|
|
|
|
title = gui.c.Tr.MergeOptionsTitle
|
2018-12-08 16:54:54 +11:00
|
|
|
} else {
|
2022-01-16 14:46:53 +11:00
|
|
|
title = gui.c.Tr.RebaseOptionsTitle
|
2018-12-08 16:54:54 +11:00
|
|
|
}
|
|
|
|
|
2022-01-29 19:09:20 +11:00
|
|
|
return gui.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
|
2018-12-08 16:54:54 +11:00
|
|
|
}
|
|
|
|
|
2019-02-16 21:01:17 +11:00
|
|
|
func (gui *Gui) genericMergeCommand(command string) error {
|
2022-01-16 14:46:53 +11:00
|
|
|
status := gui.git.Status.WorkingTreeState()
|
2018-12-08 16:54:54 +11:00
|
|
|
|
2021-12-30 13:35:10 +11:00
|
|
|
if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING {
|
2022-01-16 14:46:53 +11:00
|
|
|
return gui.c.ErrorMsg(gui.c.Tr.NotMergingOrRebasing)
|
2018-12-08 16:54:54 +11:00
|
|
|
}
|
|
|
|
|
2022-01-16 14:46:53 +11:00
|
|
|
gui.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command))
|
2021-04-10 16:01:46 +10:00
|
|
|
|
2021-12-30 12:10:09 +11:00
|
|
|
commandType := ""
|
|
|
|
switch status {
|
2021-12-30 13:35:10 +11:00
|
|
|
case enums.REBASE_MODE_MERGING:
|
2021-12-30 12:10:09 +11:00
|
|
|
commandType = "merge"
|
2021-12-30 13:35:10 +11:00
|
|
|
case enums.REBASE_MODE_REBASING:
|
2021-12-30 12:10:09 +11:00
|
|
|
commandType = "rebase"
|
2022-01-08 15:46:35 +11:00
|
|
|
default:
|
|
|
|
// shouldn't be possible to land here
|
2021-12-30 12:10:09 +11:00
|
|
|
}
|
|
|
|
|
2018-12-08 16:54:54 +11:00
|
|
|
// we should end up with a command like 'git merge --continue'
|
|
|
|
|
2018-12-11 22:16:48 +11:00
|
|
|
// it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge
|
2022-01-16 14:46:53 +11:00
|
|
|
if status == enums.REBASE_MODE_MERGING && command != REBASE_OPTION_ABORT && gui.c.UserConfig.Git.Merging.ManualCommit {
|
2022-01-08 14:10:01 +11:00
|
|
|
// TODO: see if we should be calling more of the code from gui.Git.Rebase.GenericMergeOrRebaseAction
|
2022-01-07 20:33:34 +11:00
|
|
|
return gui.runSubprocessWithSuspenseAndRefresh(
|
2022-01-16 14:46:53 +11:00
|
|
|
gui.git.Rebase.GenericMergeOrRebaseActionCmdObj(commandType, command),
|
2022-01-07 20:33:34 +11:00
|
|
|
)
|
2018-12-08 16:54:54 +11:00
|
|
|
}
|
2022-01-16 14:46:53 +11:00
|
|
|
result := gui.git.Rebase.GenericMergeOrRebaseAction(commandType, command)
|
|
|
|
if err := gui.checkMergeOrRebase(result); err != nil {
|
2019-02-16 21:01:17 +11:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2018-12-08 16:54:54 +11:00
|
|
|
|
2021-10-20 22:21:16 +11:00
|
|
|
var conflictStrings = []string{
|
|
|
|
"Failed to merge in the changes",
|
|
|
|
"When you have resolved this problem",
|
|
|
|
"fix conflicts",
|
|
|
|
"Resolve all conflicts manually",
|
|
|
|
}
|
|
|
|
|
|
|
|
func isMergeConflictErr(errStr string) bool {
|
|
|
|
for _, str := range conflictStrings {
|
|
|
|
if strings.Contains(errStr, str) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-01-16 14:46:53 +11:00
|
|
|
func (gui *Gui) checkMergeOrRebase(result error) error {
|
|
|
|
if err := gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil {
|
2019-02-16 21:01:17 +11:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if result == nil {
|
|
|
|
return nil
|
|
|
|
} else if strings.Contains(result.Error(), "No changes - did you forget to use") {
|
2021-11-01 08:58:58 +11:00
|
|
|
return gui.genericMergeCommand(REBASE_OPTION_SKIP)
|
2019-11-05 13:02:04 +11:00
|
|
|
} else if strings.Contains(result.Error(), "The previous cherry-pick is now empty") {
|
2021-11-01 08:58:58 +11:00
|
|
|
return gui.genericMergeCommand(REBASE_OPTION_CONTINUE)
|
2020-03-28 12:52:45 +11:00
|
|
|
} else if strings.Contains(result.Error(), "No rebase in progress?") {
|
|
|
|
// assume in this case that we're already done
|
|
|
|
return nil
|
2021-10-20 22:21:16 +11:00
|
|
|
} else if isMergeConflictErr(result.Error()) {
|
2022-01-29 19:09:20 +11:00
|
|
|
return gui.c.Ask(types.AskOpts{
|
2022-01-16 14:46:53 +11:00
|
|
|
Title: gui.c.Tr.FoundConflictsTitle,
|
|
|
|
Prompt: gui.c.Tr.FoundConflicts,
|
2022-01-28 20:44:36 +11:00
|
|
|
HandlersManageFocus: true,
|
|
|
|
HandleConfirm: func() error {
|
2022-01-16 14:46:53 +11:00
|
|
|
return gui.c.PushContext(gui.State.Contexts.Files)
|
2020-08-15 16:36:39 +10:00
|
|
|
},
|
2022-01-28 20:44:36 +11:00
|
|
|
HandleClose: func() error {
|
2020-08-23 19:28:59 +10:00
|
|
|
if err := gui.returnFromContext(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-11-01 08:58:58 +11:00
|
|
|
return gui.genericMergeCommand(REBASE_OPTION_ABORT)
|
2019-02-16 21:01:17 +11:00
|
|
|
},
|
2020-08-15 16:36:39 +10:00
|
|
|
})
|
2019-02-16 21:01:17 +11:00
|
|
|
} else {
|
2022-01-16 14:46:53 +11:00
|
|
|
return gui.c.ErrorMsg(result.Error())
|
2019-02-16 21:01:17 +11:00
|
|
|
}
|
2018-12-08 16:54:54 +11:00
|
|
|
}
|
2021-11-01 08:58:58 +11:00
|
|
|
|
|
|
|
func (gui *Gui) abortMergeOrRebaseWithConfirm() error {
|
|
|
|
// prompt user to confirm that they want to abort, then do it
|
|
|
|
mode := gui.workingTreeStateNoun()
|
2022-01-29 19:09:20 +11:00
|
|
|
return gui.c.Ask(types.AskOpts{
|
2022-01-16 14:46:53 +11:00
|
|
|
Title: fmt.Sprintf(gui.c.Tr.AbortTitle, mode),
|
|
|
|
Prompt: fmt.Sprintf(gui.c.Tr.AbortPrompt, mode),
|
2022-01-28 20:44:36 +11:00
|
|
|
HandleConfirm: func() error {
|
2021-11-01 08:58:58 +11:00
|
|
|
return gui.genericMergeCommand(REBASE_OPTION_ABORT)
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gui *Gui) workingTreeStateNoun() string {
|
2022-01-16 14:46:53 +11:00
|
|
|
workingTreeState := gui.git.Status.WorkingTreeState()
|
2021-11-01 08:58:58 +11:00
|
|
|
switch workingTreeState {
|
2021-12-30 13:35:10 +11:00
|
|
|
case enums.REBASE_MODE_NONE:
|
2021-11-01 08:58:58 +11:00
|
|
|
return ""
|
2021-12-30 13:35:10 +11:00
|
|
|
case enums.REBASE_MODE_MERGING:
|
2021-11-01 08:58:58 +11:00
|
|
|
return "merge"
|
|
|
|
default:
|
|
|
|
return "rebase"
|
|
|
|
}
|
|
|
|
}
|