mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-08-06 22:33:07 +02:00
Add confirmation for hard reset (#4704)
- **PR Description** Doing a hard reset is really destructive because it loses all uncommitted changes, so add a confirmation in case there are any. Fixes #3085 Fixes #3709 Fixes #4688
This commit is contained in:
@ -724,17 +724,11 @@ func (self *BranchesController) rename(branch *models.Branch) error {
|
|||||||
// I could do an explicit check here for whether the branch is tracking a remote branch
|
// I could do an explicit check here for whether the branch is tracking a remote branch
|
||||||
// but if we've selected it we'll already know that via Pullables and Pullables.
|
// but if we've selected it we'll already know that via Pullables and Pullables.
|
||||||
// Bit of a hack but I'm lazy.
|
// Bit of a hack but I'm lazy.
|
||||||
if !branch.IsTrackingRemote() {
|
return self.c.ConfirmIf(branch.IsTrackingRemote(), types.ConfirmOpts{
|
||||||
return promptForNewName()
|
|
||||||
}
|
|
||||||
|
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
|
||||||
Title: self.c.Tr.RenameBranch,
|
Title: self.c.Tr.RenameBranch,
|
||||||
Prompt: self.c.Tr.RenameBranchWarning,
|
Prompt: self.c.Tr.RenameBranchWarning,
|
||||||
HandleConfirm: promptForNewName,
|
HandleConfirm: promptForNewName,
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchesController) newBranch(selectedBranch *models.Branch) error {
|
func (self *BranchesController) newBranch(selectedBranch *models.Branch) error {
|
||||||
|
@ -426,20 +426,18 @@ func (self *CommitFilesController) toggleForPatch(selectedNodes []*filetree.Comm
|
|||||||
}
|
}
|
||||||
|
|
||||||
from, to, reverse := self.currentFromToReverseForPatchBuilding()
|
from, to, reverse := self.currentFromToReverseForPatchBuilding()
|
||||||
if self.c.Git().Patch.PatchBuilder.Active() && self.c.Git().Patch.PatchBuilder.NewPatchRequired(from, to, reverse) {
|
mustDiscardPatch := self.c.Git().Patch.PatchBuilder.Active() && self.c.Git().Patch.PatchBuilder.NewPatchRequired(from, to, reverse)
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
return self.c.ConfirmIf(mustDiscardPatch, types.ConfirmOpts{
|
||||||
Title: self.c.Tr.DiscardPatch,
|
Title: self.c.Tr.DiscardPatch,
|
||||||
Prompt: self.c.Tr.DiscardPatchConfirm,
|
Prompt: self.c.Tr.DiscardPatchConfirm,
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
|
if mustDiscardPatch {
|
||||||
self.c.Git().Patch.PatchBuilder.Reset()
|
self.c.Git().Patch.PatchBuilder.Reset()
|
||||||
return toggle()
|
}
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
return toggle()
|
||||||
}
|
},
|
||||||
|
})
|
||||||
return toggle()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitFilesController) toggleAllForPatch(_ *filetree.CommitFileNode) error {
|
func (self *CommitFilesController) toggleAllForPatch(_ *filetree.CommitFileNode) error {
|
||||||
@ -479,32 +477,26 @@ func (self *CommitFilesController) enterCommitFile(node *filetree.CommitFileNode
|
|||||||
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
|
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
|
||||||
}
|
}
|
||||||
|
|
||||||
enterTheFile := func() error {
|
|
||||||
if !self.c.Git().Patch.PatchBuilder.Active() {
|
|
||||||
if err := self.startPatchBuilder(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.c.Context().Push(self.c.Contexts().CustomPatchBuilder, opts)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
from, to, reverse := self.currentFromToReverseForPatchBuilding()
|
from, to, reverse := self.currentFromToReverseForPatchBuilding()
|
||||||
if self.c.Git().Patch.PatchBuilder.Active() && self.c.Git().Patch.PatchBuilder.NewPatchRequired(from, to, reverse) {
|
mustDiscardPatch := self.c.Git().Patch.PatchBuilder.Active() && self.c.Git().Patch.PatchBuilder.NewPatchRequired(from, to, reverse)
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
return self.c.ConfirmIf(mustDiscardPatch, types.ConfirmOpts{
|
||||||
Title: self.c.Tr.DiscardPatch,
|
Title: self.c.Tr.DiscardPatch,
|
||||||
Prompt: self.c.Tr.DiscardPatchConfirm,
|
Prompt: self.c.Tr.DiscardPatchConfirm,
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
|
if mustDiscardPatch {
|
||||||
self.c.Git().Patch.PatchBuilder.Reset()
|
self.c.Git().Patch.PatchBuilder.Reset()
|
||||||
return enterTheFile()
|
}
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
if !self.c.Git().Patch.PatchBuilder.Active() {
|
||||||
}
|
if err := self.startPatchBuilder(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return enterTheFile()
|
self.c.Context().Push(self.c.Contexts().CustomPatchBuilder, opts)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitFilesController) handleToggleCommitFileDirCollapsed(node *filetree.CommitFileNode) error {
|
func (self *CommitFilesController) handleToggleCommitFileDirCollapsed(node *filetree.CommitFileNode) error {
|
||||||
|
@ -173,28 +173,19 @@ func (self *CustomPatchOptionsMenuAction) handleMovePatchIntoWorkingTree() error
|
|||||||
|
|
||||||
self.returnFocusFromPatchExplorerIfNecessary()
|
self.returnFocusFromPatchExplorerIfNecessary()
|
||||||
|
|
||||||
pull := func(stash bool) error {
|
mustStash := self.c.Helpers().WorkingTree.IsWorkingTreeDirty()
|
||||||
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
return self.c.ConfirmIf(mustStash, types.ConfirmOpts{
|
||||||
commitIndex := self.getPatchCommitIndex()
|
Title: self.c.Tr.MustStashTitle,
|
||||||
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoIndex)
|
Prompt: self.c.Tr.MustStashWarning,
|
||||||
err := self.c.Git().Patch.MovePatchIntoIndex(self.c.Model().Commits, commitIndex, stash)
|
HandleConfirm: func() error {
|
||||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
||||||
})
|
commitIndex := self.getPatchCommitIndex()
|
||||||
}
|
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoIndex)
|
||||||
|
err := self.c.Git().Patch.MovePatchIntoIndex(self.c.Model().Commits, commitIndex, mustStash)
|
||||||
if self.c.Helpers().WorkingTree.IsWorkingTreeDirty() {
|
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
})
|
||||||
Title: self.c.Tr.MustStashTitle,
|
},
|
||||||
Prompt: self.c.Tr.MustStashWarning,
|
})
|
||||||
HandleConfirm: func() error {
|
|
||||||
return pull(true)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return pull(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
|
func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
|
||||||
@ -272,40 +263,31 @@ func (self *CustomPatchOptionsMenuAction) handleApplyPatch(reverse bool) error {
|
|||||||
|
|
||||||
affectedUnstagedFiles := self.getAffectedUnstagedFiles()
|
affectedUnstagedFiles := self.getAffectedUnstagedFiles()
|
||||||
|
|
||||||
apply := func() error {
|
mustStageFiles := len(affectedUnstagedFiles) > 0
|
||||||
action := self.c.Tr.Actions.ApplyPatch
|
return self.c.ConfirmIf(mustStageFiles, types.ConfirmOpts{
|
||||||
if reverse {
|
Title: self.c.Tr.MustStageFilesAffectedByPatchTitle,
|
||||||
action = "Apply patch in reverse"
|
Prompt: self.c.Tr.MustStageFilesAffectedByPatchWarning,
|
||||||
}
|
HandleConfirm: func() error {
|
||||||
self.c.LogAction(action)
|
action := self.c.Tr.Actions.ApplyPatch
|
||||||
|
if reverse {
|
||||||
|
action = "Apply patch in reverse"
|
||||||
|
}
|
||||||
|
self.c.LogAction(action)
|
||||||
|
|
||||||
if len(affectedUnstagedFiles) > 0 {
|
if mustStageFiles {
|
||||||
if err := self.c.Git().WorkingTree.StageFiles(affectedUnstagedFiles, nil); err != nil {
|
if err := self.c.Git().WorkingTree.StageFiles(affectedUnstagedFiles, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := self.c.Git().Patch.ApplyCustomPatch(reverse, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err := self.c.Git().Patch.ApplyCustomPatch(reverse, true); err != nil {
|
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||||
return err
|
return nil
|
||||||
}
|
},
|
||||||
|
})
|
||||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(affectedUnstagedFiles) > 0 {
|
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
|
||||||
Title: self.c.Tr.MustStageFilesAffectedByPatchTitle,
|
|
||||||
Prompt: self.c.Tr.MustStageFilesAffectedByPatchWarning,
|
|
||||||
HandleConfirm: func() error {
|
|
||||||
return apply()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return apply()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CustomPatchOptionsMenuAction) copyPatchToClipboard() error {
|
func (self *CustomPatchOptionsMenuAction) copyPatchToClipboard() error {
|
||||||
|
@ -794,19 +794,17 @@ func (self *FilesController) handleAmendCommitPress() error {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} else if !self.c.UserConfig().Gui.SkipAmendWarning {
|
}
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
|
||||||
|
return self.c.ConfirmIf(!self.c.UserConfig().Gui.SkipAmendWarning,
|
||||||
|
types.ConfirmOpts{
|
||||||
Title: self.c.Tr.AmendLastCommitTitle,
|
Title: self.c.Tr.AmendLastCommitTitle,
|
||||||
Prompt: self.c.Tr.SureToAmend,
|
Prompt: self.c.Tr.SureToAmend,
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
return doAmend()
|
return doAmend()
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
|
)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return doAmend()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FilesController) isResolvingConflicts() bool {
|
func (self *FilesController) isResolvingConflicts() bool {
|
||||||
|
@ -256,13 +256,8 @@ func (self *CommitsHelper) pasteCommitMessageFromClipboard() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentMessage := self.JoinCommitMessageAndUnwrappedDescription(); currentMessage == "" {
|
currentMessage := self.JoinCommitMessageAndUnwrappedDescription()
|
||||||
self.SetMessageAndDescriptionInView(message)
|
return self.c.ConfirmIf(currentMessage != "", types.ConfirmOpts{
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm before overwriting the commit message
|
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
|
||||||
Title: self.c.Tr.PasteCommitMessageFromClipboard,
|
Title: self.c.Tr.PasteCommitMessageFromClipboard,
|
||||||
Prompt: self.c.Tr.SurePasteCommitMessage,
|
Prompt: self.c.Tr.SurePasteCommitMessage,
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
@ -270,6 +265,4 @@ func (self *CommitsHelper) pasteCommitMessageFromClipboard() error {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -128,32 +128,22 @@ func (self *FixupHelper) HandleFindBaseCommitForFixupPress() error {
|
|||||||
// and that's the one we want to select.
|
// and that's the one we want to select.
|
||||||
_, index, _ := self.findCommit(commits, hashGroups[NOT_MERGED][0])
|
_, index, _ := self.findCommit(commits, hashGroups[NOT_MERGED][0])
|
||||||
|
|
||||||
doIt := func() error {
|
return self.c.ConfirmIf(warnAboutAddedLines, types.ConfirmOpts{
|
||||||
if !hasStagedChanges {
|
Title: self.c.Tr.FindBaseCommitForFixup,
|
||||||
if err := self.c.Git().WorkingTree.StageAll(); err != nil {
|
Prompt: self.c.Tr.HunksWithOnlyAddedLinesWarning,
|
||||||
return err
|
HandleConfirm: func() error {
|
||||||
|
if !hasStagedChanges {
|
||||||
|
if err := self.c.Git().WorkingTree.StageAll(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||||
}
|
}
|
||||||
self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
|
|
||||||
}
|
|
||||||
|
|
||||||
self.c.Contexts().LocalCommits.SetSelection(index)
|
self.c.Contexts().LocalCommits.SetSelection(index)
|
||||||
self.c.Context().Push(self.c.Contexts().LocalCommits, types.OnFocusOpts{})
|
self.c.Context().Push(self.c.Contexts().LocalCommits, types.OnFocusOpts{})
|
||||||
return nil
|
return nil
|
||||||
}
|
},
|
||||||
|
})
|
||||||
if warnAboutAddedLines {
|
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
|
||||||
Title: self.c.Tr.FindBaseCommitForFixup,
|
|
||||||
Prompt: self.c.Tr.HunksWithOnlyAddedLinesWarning,
|
|
||||||
HandleConfirm: func() error {
|
|
||||||
return doIt()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return doIt()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FixupHelper) getDiff() (string, bool, error) {
|
func (self *FixupHelper) getDiff() (string, bool, error) {
|
||||||
|
@ -248,8 +248,15 @@ func (self *RefsHelper) CreateGitResetMenu(name string, ref string) error {
|
|||||||
style.FgRed.Sprintf("reset --%s %s", row.strength, name),
|
style.FgRed.Sprintf("reset --%s %s", row.strength, name),
|
||||||
},
|
},
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
self.c.LogAction("Reset")
|
return self.c.ConfirmIf(row.strength == "hard" && IsWorkingTreeDirty(self.c.Model().Files),
|
||||||
return self.ResetToRef(ref, row.strength, []string{})
|
types.ConfirmOpts{
|
||||||
|
Title: self.c.Tr.Actions.HardReset,
|
||||||
|
Prompt: self.c.Tr.ResetHardConfirmation,
|
||||||
|
HandleConfirm: func() error {
|
||||||
|
self.c.LogAction("Reset")
|
||||||
|
return self.ResetToRef(ref, row.strength, []string{})
|
||||||
|
},
|
||||||
|
})
|
||||||
},
|
},
|
||||||
Key: row.key,
|
Key: row.key,
|
||||||
Tooltip: row.tooltip,
|
Tooltip: row.tooltip,
|
||||||
|
@ -23,43 +23,34 @@ func NewTagsHelper(c *HelperCommon, commitsHelper *CommitsHelper, gpg *GpgHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error {
|
func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error {
|
||||||
doCreateTag := func(tagName string, description string, force bool) error {
|
|
||||||
var command *oscommands.CmdObj
|
|
||||||
if description != "" || self.c.Git().Config.GetGpgTagSign() {
|
|
||||||
self.c.LogAction(self.c.Tr.Actions.CreateAnnotatedTag)
|
|
||||||
command = self.c.Git().Tag.CreateAnnotatedObj(tagName, ref, description, force)
|
|
||||||
} else {
|
|
||||||
self.c.LogAction(self.c.Tr.Actions.CreateLightweightTag)
|
|
||||||
command = self.c.Git().Tag.CreateLightweightObj(tagName, ref, force)
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.gpg.WithGpgHandling(command, git_commands.TagGpgSign, self.c.Tr.CreatingTag, func() error {
|
|
||||||
return nil
|
|
||||||
}, []types.RefreshableView{types.COMMITS, types.TAGS})
|
|
||||||
}
|
|
||||||
|
|
||||||
onConfirm := func(tagName string, description string) error {
|
onConfirm := func(tagName string, description string) error {
|
||||||
if self.c.Git().Tag.HasTag(tagName) {
|
prompt := utils.ResolvePlaceholderString(
|
||||||
prompt := utils.ResolvePlaceholderString(
|
self.c.Tr.ForceTagPrompt,
|
||||||
self.c.Tr.ForceTagPrompt,
|
map[string]string{
|
||||||
map[string]string{
|
"tagName": tagName,
|
||||||
"tagName": tagName,
|
"cancelKey": self.c.UserConfig().Keybinding.Universal.Return,
|
||||||
"cancelKey": self.c.UserConfig().Keybinding.Universal.Return,
|
"confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm,
|
||||||
"confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm,
|
},
|
||||||
},
|
)
|
||||||
)
|
force := self.c.Git().Tag.HasTag(tagName)
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
return self.c.ConfirmIf(force, types.ConfirmOpts{
|
||||||
Title: self.c.Tr.ForceTag,
|
Title: self.c.Tr.ForceTag,
|
||||||
Prompt: prompt,
|
Prompt: prompt,
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
return doCreateTag(tagName, description, true)
|
var command *oscommands.CmdObj
|
||||||
},
|
if description != "" || self.c.Git().Config.GetGpgTagSign() {
|
||||||
})
|
self.c.LogAction(self.c.Tr.Actions.CreateAnnotatedTag)
|
||||||
|
command = self.c.Git().Tag.CreateAnnotatedObj(tagName, ref, description, force)
|
||||||
|
} else {
|
||||||
|
self.c.LogAction(self.c.Tr.Actions.CreateLightweightTag)
|
||||||
|
command = self.c.Git().Tag.CreateLightweightObj(tagName, ref, force)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return self.gpg.WithGpgHandling(command, git_commands.TagGpgSign, self.c.Tr.CreatingTag, func() error {
|
||||||
}
|
return nil
|
||||||
|
}, []types.RefreshableView{types.COMMITS, types.TAGS})
|
||||||
return doCreateTag(tagName, description, false)
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
self.commitsHelper.OpenCommitMessagePanel(
|
self.commitsHelper.OpenCommitMessagePanel(
|
||||||
|
@ -435,17 +435,12 @@ func (self *LocalCommitsController) doRewordEditor() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) rewordEditor(commit *models.Commit) error {
|
func (self *LocalCommitsController) rewordEditor(commit *models.Commit) error {
|
||||||
if self.c.UserConfig().Gui.SkipRewordInEditorWarning {
|
return self.c.ConfirmIf(!self.c.UserConfig().Gui.SkipRewordInEditorWarning,
|
||||||
return self.doRewordEditor()
|
types.ConfirmOpts{
|
||||||
}
|
Title: self.c.Tr.RewordInEditorTitle,
|
||||||
|
Prompt: self.c.Tr.RewordInEditorPrompt,
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
HandleConfirm: self.doRewordEditor,
|
||||||
Title: self.c.Tr.RewordInEditorTitle,
|
})
|
||||||
Prompt: self.c.Tr.RewordInEditorPrompt,
|
|
||||||
HandleConfirm: self.doRewordEditor,
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) drop(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
func (self *LocalCommitsController) drop(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
@ -749,17 +744,12 @@ func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.UserConfig().Gui.SkipAmendWarning {
|
return self.c.ConfirmIf(!self.c.UserConfig().Gui.SkipAmendWarning,
|
||||||
return handleCommit()
|
types.ConfirmOpts{
|
||||||
}
|
Title: self.c.Tr.AmendCommitTitle,
|
||||||
|
Prompt: self.c.Tr.AmendCommitPrompt,
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
HandleConfirm: handleCommit,
|
||||||
Title: self.c.Tr.AmendCommitTitle,
|
})
|
||||||
Prompt: self.c.Tr.AmendCommitPrompt,
|
|
||||||
HandleConfirm: handleCommit,
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) canAmendRange(commits []*models.Commit, start, end int) *types.DisabledReason {
|
func (self *LocalCommitsController) canAmendRange(commits []*models.Commit, start, end int) *types.DisabledReason {
|
||||||
|
@ -25,19 +25,14 @@ func (self *QuitActions) quitAux() error {
|
|||||||
return self.confirmQuitDuringUpdate()
|
return self.confirmQuitDuringUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.UserConfig().ConfirmOnQuit {
|
return self.c.ConfirmIf(self.c.UserConfig().ConfirmOnQuit,
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
types.ConfirmOpts{
|
||||||
Title: "",
|
Title: "",
|
||||||
Prompt: self.c.Tr.ConfirmQuit,
|
Prompt: self.c.Tr.ConfirmQuit,
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
return gocui.ErrQuit
|
return gocui.ErrQuit
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return gocui.ErrQuit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *QuitActions) confirmQuitDuringUpdate() error {
|
func (self *QuitActions) confirmQuitDuringUpdate() error {
|
||||||
|
@ -201,19 +201,12 @@ func (self *StagingController) DiscardSelection() error {
|
|||||||
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
|
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
|
||||||
}
|
}
|
||||||
|
|
||||||
reset := func() error { return self.applySelectionAndRefresh(true) }
|
return self.c.ConfirmIf(!self.staged && !self.c.UserConfig().Gui.SkipDiscardChangeWarning,
|
||||||
|
types.ConfirmOpts{
|
||||||
if !self.staged && !self.c.UserConfig().Gui.SkipDiscardChangeWarning {
|
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
|
||||||
Title: self.c.Tr.DiscardChangeTitle,
|
Title: self.c.Tr.DiscardChangeTitle,
|
||||||
Prompt: self.c.Tr.DiscardChangePrompt,
|
Prompt: self.c.Tr.DiscardChangePrompt,
|
||||||
HandleConfirm: reset,
|
HandleConfirm: func() error { return self.applySelectionAndRefresh(true) },
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return reset()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StagingController) applySelectionAndRefresh(reverse bool) error {
|
func (self *StagingController) applySelectionAndRefresh(reverse bool) error {
|
||||||
|
@ -107,32 +107,23 @@ func (self *StashController) context() *context.StashContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StashController) handleStashApply(stashEntry *models.StashEntry) error {
|
func (self *StashController) handleStashApply(stashEntry *models.StashEntry) error {
|
||||||
apply := func() error {
|
return self.c.ConfirmIf(!self.c.UserConfig().Gui.SkipStashWarning,
|
||||||
self.c.LogAction(self.c.Tr.Actions.Stash)
|
types.ConfirmOpts{
|
||||||
err := self.c.Git().Stash.Apply(stashEntry.Index)
|
Title: self.c.Tr.StashApply,
|
||||||
self.postStashRefresh()
|
Prompt: self.c.Tr.SureApplyStashEntry,
|
||||||
if err != nil {
|
HandleConfirm: func() error {
|
||||||
return err
|
self.c.LogAction(self.c.Tr.Actions.Stash)
|
||||||
}
|
err := self.c.Git().Stash.Apply(stashEntry.Index)
|
||||||
if self.c.UserConfig().Gui.SwitchToFilesAfterStashApply {
|
self.postStashRefresh()
|
||||||
self.c.Context().Push(self.c.Contexts().Files, types.OnFocusOpts{})
|
if err != nil {
|
||||||
}
|
return err
|
||||||
return nil
|
}
|
||||||
}
|
if self.c.UserConfig().Gui.SwitchToFilesAfterStashApply {
|
||||||
|
self.c.Context().Push(self.c.Contexts().Files, types.OnFocusOpts{})
|
||||||
if self.c.UserConfig().Gui.SkipStashWarning {
|
}
|
||||||
return apply()
|
return nil
|
||||||
}
|
},
|
||||||
|
})
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
|
||||||
Title: self.c.Tr.StashApply,
|
|
||||||
Prompt: self.c.Tr.SureApplyStashEntry,
|
|
||||||
HandleConfirm: func() error {
|
|
||||||
return apply()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StashController) handleStashPop(stashEntry *models.StashEntry) error {
|
func (self *StashController) handleStashPop(stashEntry *models.StashEntry) error {
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
)
|
)
|
||||||
@ -150,15 +151,22 @@ func (self *FilesController) createResetMenu() error {
|
|||||||
red.Sprint("git reset --hard HEAD"),
|
red.Sprint("git reset --hard HEAD"),
|
||||||
},
|
},
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.HardReset)
|
return self.c.ConfirmIf(helpers.IsWorkingTreeDirty(self.c.Model().Files),
|
||||||
if err := self.c.Git().WorkingTree.ResetHard("HEAD"); err != nil {
|
types.ConfirmOpts{
|
||||||
return err
|
Title: self.c.Tr.Actions.HardReset,
|
||||||
}
|
Prompt: self.c.Tr.ResetHardConfirmation,
|
||||||
|
HandleConfirm: func() error {
|
||||||
|
self.c.LogAction(self.c.Tr.Actions.HardReset)
|
||||||
|
if err := self.c.Git().WorkingTree.ResetHard("HEAD"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
self.c.Refresh(
|
self.c.Refresh(
|
||||||
types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}},
|
types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}},
|
||||||
)
|
)
|
||||||
return nil
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
},
|
},
|
||||||
Key: 'h',
|
Key: 'h',
|
||||||
},
|
},
|
||||||
|
@ -115,6 +115,20 @@ func (self *PopupHandler) Confirm(opts types.ConfirmOpts) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *PopupHandler) ConfirmIf(condition bool, opts types.ConfirmOpts) error {
|
||||||
|
if condition {
|
||||||
|
self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{
|
||||||
|
Title: opts.Title,
|
||||||
|
Prompt: opts.Prompt,
|
||||||
|
HandleConfirm: opts.HandleConfirm,
|
||||||
|
HandleClose: opts.HandleClose,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts.HandleConfirm()
|
||||||
|
}
|
||||||
|
|
||||||
func (self *PopupHandler) Prompt(opts types.PromptOpts) {
|
func (self *PopupHandler) Prompt(opts types.PromptOpts) {
|
||||||
self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{
|
self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{
|
||||||
Title: opts.Title,
|
Title: opts.Title,
|
||||||
|
@ -126,6 +126,8 @@ type IPopupHandler interface {
|
|||||||
Alert(title string, message string)
|
Alert(title string, message string)
|
||||||
// Shows a popup asking the user for confirmation.
|
// Shows a popup asking the user for confirmation.
|
||||||
Confirm(opts ConfirmOpts)
|
Confirm(opts ConfirmOpts)
|
||||||
|
// Shows a popup asking the user for confirmation if condition is true; otherwise, the HandleConfirm function is called directly.
|
||||||
|
ConfirmIf(condition bool, opts ConfirmOpts) error
|
||||||
// Shows a popup prompting the user for input.
|
// Shows a popup prompting the user for input.
|
||||||
Prompt(opts PromptOpts)
|
Prompt(opts PromptOpts)
|
||||||
WithWaitingStatus(message string, f func(gocui.Task) error) error
|
WithWaitingStatus(message string, f func(gocui.Task) error) error
|
||||||
|
@ -479,6 +479,7 @@ type TranslationSet struct {
|
|||||||
ResetSoftTooltip string
|
ResetSoftTooltip string
|
||||||
ResetMixedTooltip string
|
ResetMixedTooltip string
|
||||||
ResetHardTooltip string
|
ResetHardTooltip string
|
||||||
|
ResetHardConfirmation string
|
||||||
PressEnterToReturn string
|
PressEnterToReturn string
|
||||||
ViewStashOptions string
|
ViewStashOptions string
|
||||||
ViewStashOptionsTooltip string
|
ViewStashOptionsTooltip string
|
||||||
@ -1502,6 +1503,7 @@ func EnglishTranslationSet() *TranslationSet {
|
|||||||
ResetSoftTooltip: "Reset HEAD to the chosen commit, and keep the changes between the current and chosen commit as staged changes.",
|
ResetSoftTooltip: "Reset HEAD to the chosen commit, and keep the changes between the current and chosen commit as staged changes.",
|
||||||
ResetMixedTooltip: "Reset HEAD to the chosen commit, and keep the changes between the current and chosen commit as unstaged changes.",
|
ResetMixedTooltip: "Reset HEAD to the chosen commit, and keep the changes between the current and chosen commit as unstaged changes.",
|
||||||
ResetHardTooltip: "Reset HEAD to the chosen commit, and discard all changes between the current and chosen commit, as well as all current modifications in the working tree.",
|
ResetHardTooltip: "Reset HEAD to the chosen commit, and discard all changes between the current and chosen commit, as well as all current modifications in the working tree.",
|
||||||
|
ResetHardConfirmation: "Are you sure you want to do a hard reset? This will discard all uncommitted changes (both staged and unstaged), which is not undoable.",
|
||||||
ViewResetOptions: `Reset`,
|
ViewResetOptions: `Reset`,
|
||||||
FileResetOptionsTooltip: "View reset options for working tree (e.g. nuking the working tree).",
|
FileResetOptionsTooltip: "View reset options for working tree (e.g. nuking the working tree).",
|
||||||
FixupTooltip: "Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded.",
|
FixupTooltip: "Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded.",
|
||||||
|
@ -97,6 +97,11 @@ var ResetToUpstream = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Title(Equals("Reset to origin/hard-branch")).
|
Title(Equals("Reset to origin/hard-branch")).
|
||||||
Select(Contains("Hard reset")).
|
Select(Contains("Hard reset")).
|
||||||
Confirm()
|
Confirm()
|
||||||
|
|
||||||
|
t.ExpectPopup().Confirmation().
|
||||||
|
Title(Equals("Hard reset")).
|
||||||
|
Content(Contains("Are you sure you want to do a hard reset?")).
|
||||||
|
Confirm()
|
||||||
})
|
})
|
||||||
t.Views().Commits().Lines(Contains("hard commit"))
|
t.Views().Commits().Lines(Contains("hard commit"))
|
||||||
t.Views().Files().IsEmpty()
|
t.Views().Files().IsEmpty()
|
||||||
|
Reference in New Issue
Block a user