mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-05 00:59:19 +02:00
Merge pull request #2298 from arnaudperalta/commit-in-staged-menu
Closes undefined
This commit is contained in:
@ -191,6 +191,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
|||||||
<kbd>space</kbd>: toggle line staged / unstaged
|
<kbd>space</kbd>: toggle line staged / unstaged
|
||||||
<kbd>d</kbd>: delete change (git reset)
|
<kbd>d</kbd>: delete change (git reset)
|
||||||
<kbd>E</kbd>: edit hunk
|
<kbd>E</kbd>: edit hunk
|
||||||
|
<kbd>c</kbd>: commit changes
|
||||||
|
<kbd>w</kbd>: commit changes without pre-commit hook
|
||||||
|
<kbd>C</kbd>: commit changes using git editor
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Reflog
|
## Reflog
|
||||||
|
@ -251,6 +251,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
|||||||
<kbd>space</kbd>: 選択行をステージ/アンステージ
|
<kbd>space</kbd>: 選択行をステージ/アンステージ
|
||||||
<kbd>d</kbd>: 変更を削除 (git reset)
|
<kbd>d</kbd>: 変更を削除 (git reset)
|
||||||
<kbd>E</kbd>: edit hunk
|
<kbd>E</kbd>: edit hunk
|
||||||
|
<kbd>c</kbd>: 変更をコミット
|
||||||
|
<kbd>w</kbd>: pre-commitフックを実行せずに変更をコミット
|
||||||
|
<kbd>C</kbd>: gitエディタを使用して変更をコミット
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## リモート
|
## リモート
|
||||||
|
@ -136,6 +136,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
|||||||
<kbd>space</kbd>: 선택한 행을 staged / unstaged
|
<kbd>space</kbd>: 선택한 행을 staged / unstaged
|
||||||
<kbd>d</kbd>: 변경을 삭제 (git reset)
|
<kbd>d</kbd>: 변경을 삭제 (git reset)
|
||||||
<kbd>E</kbd>: edit hunk
|
<kbd>E</kbd>: edit hunk
|
||||||
|
<kbd>c</kbd>: 커밋 변경내용
|
||||||
|
<kbd>w</kbd>: commit changes without pre-commit hook
|
||||||
|
<kbd>C</kbd>: Git 편집기를 사용하여 변경 내용을 커밋합니다.
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 브랜치
|
## 브랜치
|
||||||
|
@ -229,6 +229,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
|||||||
<kbd>space</kbd>: toggle lijnen staged / unstaged
|
<kbd>space</kbd>: toggle lijnen staged / unstaged
|
||||||
<kbd>d</kbd>: verwijdert change (git reset)
|
<kbd>d</kbd>: verwijdert change (git reset)
|
||||||
<kbd>E</kbd>: edit hunk
|
<kbd>E</kbd>: edit hunk
|
||||||
|
<kbd>c</kbd>: commit veranderingen
|
||||||
|
<kbd>w</kbd>: commit veranderingen zonder pre-commit hook
|
||||||
|
<kbd>C</kbd>: commit veranderingen met de git editor
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Stash
|
## Stash
|
||||||
|
@ -168,6 +168,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
|||||||
<kbd>space</kbd>: toggle line staged / unstaged
|
<kbd>space</kbd>: toggle line staged / unstaged
|
||||||
<kbd>d</kbd>: delete change (git reset)
|
<kbd>d</kbd>: delete change (git reset)
|
||||||
<kbd>E</kbd>: edit hunk
|
<kbd>E</kbd>: edit hunk
|
||||||
|
<kbd>c</kbd>: Zatwierdź zmiany
|
||||||
|
<kbd>w</kbd>: zatwierdź zmiany bez skryptu pre-commit
|
||||||
|
<kbd>C</kbd>: Zatwierdź zmiany używając edytora
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Reflog
|
## Reflog
|
||||||
|
@ -238,6 +238,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
|||||||
<kbd>space</kbd>: 切换行暂存状态
|
<kbd>space</kbd>: 切换行暂存状态
|
||||||
<kbd>d</kbd>: 取消变更 (git reset)
|
<kbd>d</kbd>: 取消变更 (git reset)
|
||||||
<kbd>E</kbd>: edit hunk
|
<kbd>E</kbd>: edit hunk
|
||||||
|
<kbd>c</kbd>: 提交更改
|
||||||
|
<kbd>w</kbd>: 提交更改而无需预先提交钩子
|
||||||
|
<kbd>C</kbd>: 提交更改(使用编辑器编辑提交信息)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 正常
|
## 正常
|
||||||
|
@ -24,6 +24,10 @@ func (gui *Gui) resetControllers() {
|
|||||||
|
|
||||||
rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, refsHelper)
|
rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, refsHelper)
|
||||||
suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions)
|
suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions)
|
||||||
|
setCommitMessage := gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage })
|
||||||
|
getSavedCommitMessage := func() string {
|
||||||
|
return gui.State.savedCommitMessage
|
||||||
|
}
|
||||||
gui.helpers = &helpers.Helpers{
|
gui.helpers = &helpers.Helpers{
|
||||||
Refs: refsHelper,
|
Refs: refsHelper,
|
||||||
Host: helpers.NewHostHelper(helperCommon, gui.git),
|
Host: helpers.NewHostHelper(helperCommon, gui.git),
|
||||||
@ -31,7 +35,7 @@ func (gui *Gui) resetControllers() {
|
|||||||
Bisect: helpers.NewBisectHelper(helperCommon, gui.git),
|
Bisect: helpers.NewBisectHelper(helperCommon, gui.git),
|
||||||
Suggestions: suggestionsHelper,
|
Suggestions: suggestionsHelper,
|
||||||
Files: helpers.NewFilesHelper(helperCommon, gui.git, osCommand),
|
Files: helpers.NewFilesHelper(helperCommon, gui.git, osCommand),
|
||||||
WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, gui.git, model),
|
WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, gui.git, gui.State.Contexts, refsHelper, model, setCommitMessage, getSavedCommitMessage),
|
||||||
Tags: helpers.NewTagsHelper(helperCommon, gui.git),
|
Tags: helpers.NewTagsHelper(helperCommon, gui.git),
|
||||||
GPG: helpers.NewGpgHelper(helperCommon, gui.os, gui.git),
|
GPG: helpers.NewGpgHelper(helperCommon, gui.os, gui.git),
|
||||||
MergeAndRebase: rebaseHelper,
|
MergeAndRebase: rebaseHelper,
|
||||||
@ -76,16 +80,10 @@ func (gui *Gui) resetControllers() {
|
|||||||
|
|
||||||
bisectController := controllers.NewBisectController(common)
|
bisectController := controllers.NewBisectController(common)
|
||||||
|
|
||||||
getSavedCommitMessage := func() string {
|
|
||||||
return gui.State.savedCommitMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
getCommitMessage := func() string {
|
getCommitMessage := func() string {
|
||||||
return strings.TrimSpace(gui.Views.CommitMessage.TextArea.GetContent())
|
return strings.TrimSpace(gui.Views.CommitMessage.TextArea.GetContent())
|
||||||
}
|
}
|
||||||
|
|
||||||
setCommitMessage := gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage })
|
|
||||||
|
|
||||||
onCommitAttempt := func(message string) {
|
onCommitAttempt := func(message string) {
|
||||||
gui.State.savedCommitMessage = message
|
gui.State.savedCommitMessage = message
|
||||||
gui.Views.CommitMessage.ClearTextArea()
|
gui.Views.CommitMessage.ClearTextArea()
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type FilesController struct {
|
type FilesController struct {
|
||||||
@ -54,12 +50,12 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Files.CommitChanges),
|
Key: opts.GetKey(opts.Config.Files.CommitChanges),
|
||||||
Handler: self.HandleCommitPress,
|
Handler: self.helpers.WorkingTree.HandleCommitPress,
|
||||||
Description: self.c.Tr.CommitChanges,
|
Description: self.c.Tr.CommitChanges,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Files.CommitChangesWithoutHook),
|
Key: opts.GetKey(opts.Config.Files.CommitChangesWithoutHook),
|
||||||
Handler: self.HandleWIPCommitPress,
|
Handler: self.helpers.WorkingTree.HandleWIPCommitPress,
|
||||||
Description: self.c.Tr.LcCommitChangesWithoutHook,
|
Description: self.c.Tr.LcCommitChangesWithoutHook,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -69,7 +65,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Files.CommitChangesWithEditor),
|
Key: opts.GetKey(opts.Config.Files.CommitChangesWithEditor),
|
||||||
Handler: self.HandleCommitEditorPress,
|
Handler: self.helpers.WorkingTree.HandleCommitEditorPress,
|
||||||
Description: self.c.Tr.CommitChangesWithEditor,
|
Description: self.c.Tr.CommitChangesWithEditor,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -554,112 +550,17 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FilesController) HandleWIPCommitPress() error {
|
|
||||||
skipHookPrefix := self.c.UserConfig.Git.SkipHookPrefix
|
|
||||||
if skipHookPrefix == "" {
|
|
||||||
return self.c.ErrorMsg(self.c.Tr.SkipHookPrefixNotConfigured)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.setCommitMessage(skipHookPrefix)
|
|
||||||
|
|
||||||
return self.HandleCommitPress()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *FilesController) commitPrefixConfigForRepo() *config.CommitPrefixConfig {
|
|
||||||
cfg, ok := self.c.UserConfig.Git.CommitPrefixes[utils.GetCurrentRepoName()]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *FilesController) prepareFilesForCommit() error {
|
|
||||||
noStagedFiles := !self.helpers.WorkingTree.AnyStagedFiles()
|
|
||||||
if noStagedFiles && self.c.UserConfig.Gui.SkipNoStagedFilesWarning {
|
|
||||||
self.c.LogAction(self.c.Tr.Actions.StageAllFiles)
|
|
||||||
err := self.git.WorkingTree.StageAll()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.syncRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// for when you need to refetch files before continuing an action. Runs synchronously.
|
|
||||||
func (self *FilesController) syncRefresh() error {
|
|
||||||
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *FilesController) refresh() error {
|
func (self *FilesController) refresh() error {
|
||||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FilesController) HandleCommitPress() error {
|
|
||||||
if err := self.prepareFilesForCommit(); err != nil {
|
|
||||||
return self.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(self.model.Files) == 0 {
|
|
||||||
return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.helpers.WorkingTree.AnyStagedFiles() {
|
|
||||||
return self.promptToStageAllAndRetry(self.HandleCommitPress)
|
|
||||||
}
|
|
||||||
|
|
||||||
savedCommitMessage := self.getSavedCommitMessage()
|
|
||||||
if len(savedCommitMessage) > 0 {
|
|
||||||
self.setCommitMessage(savedCommitMessage)
|
|
||||||
} else {
|
|
||||||
commitPrefixConfig := self.commitPrefixConfigForRepo()
|
|
||||||
if commitPrefixConfig != nil {
|
|
||||||
prefixPattern := commitPrefixConfig.Pattern
|
|
||||||
prefixReplace := commitPrefixConfig.Replace
|
|
||||||
rgx, err := regexp.Compile(prefixPattern)
|
|
||||||
if err != nil {
|
|
||||||
return self.c.ErrorMsg(fmt.Sprintf("%s: %s", self.c.Tr.LcCommitPrefixPatternError, err.Error()))
|
|
||||||
}
|
|
||||||
prefix := rgx.ReplaceAllString(self.helpers.Refs.GetCheckedOutRef().Name, prefixReplace)
|
|
||||||
self.setCommitMessage(prefix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := self.c.PushContext(self.contexts.CommitMessage); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *FilesController) promptToStageAllAndRetry(retry func() error) error {
|
|
||||||
return self.c.Confirm(types.ConfirmOpts{
|
|
||||||
Title: self.c.Tr.NoFilesStagedTitle,
|
|
||||||
Prompt: self.c.Tr.NoFilesStagedPrompt,
|
|
||||||
HandleConfirm: func() error {
|
|
||||||
self.c.LogAction(self.c.Tr.Actions.StageAllFiles)
|
|
||||||
if err := self.git.WorkingTree.StageAll(); err != nil {
|
|
||||||
return self.c.Error(err)
|
|
||||||
}
|
|
||||||
if err := self.syncRefresh(); err != nil {
|
|
||||||
return self.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return retry()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *FilesController) handleAmendCommitPress() error {
|
func (self *FilesController) handleAmendCommitPress() error {
|
||||||
if len(self.model.Files) == 0 {
|
if len(self.model.Files) == 0 {
|
||||||
return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle)
|
return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.helpers.WorkingTree.AnyStagedFiles() {
|
if !self.helpers.WorkingTree.AnyStagedFiles() {
|
||||||
return self.promptToStageAllAndRetry(self.handleAmendCommitPress)
|
return self.helpers.WorkingTree.PromptToStageAllAndRetry(self.handleAmendCommitPress)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(self.model.Commits) == 0 {
|
if len(self.model.Commits) == 0 {
|
||||||
@ -677,23 +578,6 @@ func (self *FilesController) handleAmendCommitPress() error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleCommitEditorPress - handle when the user wants to commit changes via
|
|
||||||
// their editor rather than via the popup panel
|
|
||||||
func (self *FilesController) HandleCommitEditorPress() error {
|
|
||||||
if len(self.model.Files) == 0 {
|
|
||||||
return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.helpers.WorkingTree.AnyStagedFiles() {
|
|
||||||
return self.promptToStageAllAndRetry(self.HandleCommitEditorPress)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.c.LogAction(self.c.Tr.Actions.Commit)
|
|
||||||
return self.c.RunSubprocessAndRefresh(
|
|
||||||
self.git.Commit.CommitEditorCmdObj(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *FilesController) handleStatusFilterPressed() error {
|
func (self *FilesController) handleStatusFilterPressed() error {
|
||||||
return self.c.Menu(types.CreateMenuOptions{
|
return self.c.Menu(types.CreateMenuOptions{
|
||||||
Title: self.c.Tr.FilteringMenuTitle,
|
Title: self.c.Tr.FilteringMenuTitle,
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
package helpers
|
package helpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IWorkingTreeHelper interface {
|
type IWorkingTreeHelper interface {
|
||||||
@ -14,17 +20,32 @@ type IWorkingTreeHelper interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WorkingTreeHelper struct {
|
type WorkingTreeHelper struct {
|
||||||
c *types.HelperCommon
|
c *types.HelperCommon
|
||||||
git *commands.GitCommand
|
git *commands.GitCommand
|
||||||
|
contexts *context.ContextTree
|
||||||
model *types.Model
|
refHelper *RefsHelper
|
||||||
|
model *types.Model
|
||||||
|
setCommitMessage func(message string)
|
||||||
|
getSavedCommitMessage func() string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWorkingTreeHelper(c *types.HelperCommon, git *commands.GitCommand, model *types.Model) *WorkingTreeHelper {
|
func NewWorkingTreeHelper(
|
||||||
|
c *types.HelperCommon,
|
||||||
|
git *commands.GitCommand,
|
||||||
|
contexts *context.ContextTree,
|
||||||
|
refHelper *RefsHelper,
|
||||||
|
model *types.Model,
|
||||||
|
setCommitMessage func(message string),
|
||||||
|
getSavedCommitMessage func() string,
|
||||||
|
) *WorkingTreeHelper {
|
||||||
return &WorkingTreeHelper{
|
return &WorkingTreeHelper{
|
||||||
c: c,
|
c: c,
|
||||||
git: git,
|
git: git,
|
||||||
model: model,
|
contexts: contexts,
|
||||||
|
refHelper: refHelper,
|
||||||
|
model: model,
|
||||||
|
setCommitMessage: setCommitMessage,
|
||||||
|
getSavedCommitMessage: getSavedCommitMessage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,3 +93,115 @@ func (self *WorkingTreeHelper) OpenMergeTool() error {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *WorkingTreeHelper) HandleCommitPress() error {
|
||||||
|
if err := self.prepareFilesForCommit(); err != nil {
|
||||||
|
return self.c.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(self.model.Files) == 0 {
|
||||||
|
return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.AnyStagedFiles() {
|
||||||
|
return self.PromptToStageAllAndRetry(self.HandleCommitPress)
|
||||||
|
}
|
||||||
|
|
||||||
|
savedCommitMessage := self.getSavedCommitMessage()
|
||||||
|
if len(savedCommitMessage) > 0 {
|
||||||
|
self.setCommitMessage(savedCommitMessage)
|
||||||
|
} else {
|
||||||
|
commitPrefixConfig := self.commitPrefixConfigForRepo()
|
||||||
|
if commitPrefixConfig != nil {
|
||||||
|
prefixPattern := commitPrefixConfig.Pattern
|
||||||
|
prefixReplace := commitPrefixConfig.Replace
|
||||||
|
rgx, err := regexp.Compile(prefixPattern)
|
||||||
|
if err != nil {
|
||||||
|
return self.c.ErrorMsg(fmt.Sprintf("%s: %s", self.c.Tr.LcCommitPrefixPatternError, err.Error()))
|
||||||
|
}
|
||||||
|
prefix := rgx.ReplaceAllString(self.refHelper.GetCheckedOutRef().Name, prefixReplace)
|
||||||
|
self.setCommitMessage(prefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := self.c.PushContext(self.contexts.CommitMessage); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleCommitEditorPress - handle when the user wants to commit changes via
|
||||||
|
// their editor rather than via the popup panel
|
||||||
|
func (self *WorkingTreeHelper) HandleCommitEditorPress() error {
|
||||||
|
if len(self.model.Files) == 0 {
|
||||||
|
return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.AnyStagedFiles() {
|
||||||
|
return self.PromptToStageAllAndRetry(self.HandleCommitEditorPress)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.c.LogAction(self.c.Tr.Actions.Commit)
|
||||||
|
return self.c.RunSubprocessAndRefresh(
|
||||||
|
self.git.Commit.CommitEditorCmdObj(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WorkingTreeHelper) HandleWIPCommitPress() error {
|
||||||
|
skipHookPrefix := self.c.UserConfig.Git.SkipHookPrefix
|
||||||
|
if skipHookPrefix == "" {
|
||||||
|
return self.c.ErrorMsg(self.c.Tr.SkipHookPrefixNotConfigured)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setCommitMessage(skipHookPrefix)
|
||||||
|
|
||||||
|
return self.HandleCommitPress()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WorkingTreeHelper) PromptToStageAllAndRetry(retry func() error) error {
|
||||||
|
return self.c.Confirm(types.ConfirmOpts{
|
||||||
|
Title: self.c.Tr.NoFilesStagedTitle,
|
||||||
|
Prompt: self.c.Tr.NoFilesStagedPrompt,
|
||||||
|
HandleConfirm: func() error {
|
||||||
|
self.c.LogAction(self.c.Tr.Actions.StageAllFiles)
|
||||||
|
if err := self.git.WorkingTree.StageAll(); err != nil {
|
||||||
|
return self.c.Error(err)
|
||||||
|
}
|
||||||
|
if err := self.syncRefresh(); err != nil {
|
||||||
|
return self.c.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return retry()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// for when you need to refetch files before continuing an action. Runs synchronously.
|
||||||
|
func (self *WorkingTreeHelper) syncRefresh() error {
|
||||||
|
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WorkingTreeHelper) prepareFilesForCommit() error {
|
||||||
|
noStagedFiles := !self.AnyStagedFiles()
|
||||||
|
if noStagedFiles && self.c.UserConfig.Gui.SkipNoStagedFilesWarning {
|
||||||
|
self.c.LogAction(self.c.Tr.Actions.StageAllFiles)
|
||||||
|
err := self.git.WorkingTree.StageAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.syncRefresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WorkingTreeHelper) commitPrefixConfigForRepo() *config.CommitPrefixConfig {
|
||||||
|
cfg, ok := self.c.UserConfig.Git.CommitPrefixes[utils.GetCurrentRepoName()]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cfg
|
||||||
|
}
|
||||||
|
@ -73,6 +73,21 @@ func (self *StagingController) GetKeybindings(opts types.KeybindingsOpts) []*typ
|
|||||||
Handler: self.EditHunkAndRefresh,
|
Handler: self.EditHunkAndRefresh,
|
||||||
Description: self.c.Tr.EditHunk,
|
Description: self.c.Tr.EditHunk,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Key: opts.GetKey(opts.Config.Files.CommitChanges),
|
||||||
|
Handler: self.helpers.WorkingTree.HandleCommitPress,
|
||||||
|
Description: self.c.Tr.CommitChanges,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: opts.GetKey(opts.Config.Files.CommitChangesWithoutHook),
|
||||||
|
Handler: self.helpers.WorkingTree.HandleWIPCommitPress,
|
||||||
|
Description: self.c.Tr.LcCommitChangesWithoutHook,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: opts.GetKey(opts.Config.Files.CommitChangesWithEditor),
|
||||||
|
Handler: self.helpers.WorkingTree.HandleCommitEditorPress,
|
||||||
|
Description: self.c.Tr.CommitChangesWithEditor,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
pkg/integration/tests/commit/staged.go
Normal file
34
pkg/integration/tests/commit/staged.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package commit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Staged = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Staging a couple files, going in the staged files menu, unstaging a line then committing",
|
||||||
|
ExtraCmdArgs: "",
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.
|
||||||
|
CreateFile("myfile", "myfile content\nwith a second line").
|
||||||
|
CreateFile("myfile2", "myfile2 content")
|
||||||
|
},
|
||||||
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
|
assert.CommitCount(0)
|
||||||
|
|
||||||
|
input.PrimaryAction()
|
||||||
|
input.Confirm()
|
||||||
|
input.PrimaryAction()
|
||||||
|
input.PressKeys(keys.Files.CommitChanges)
|
||||||
|
|
||||||
|
commitMessage := "my commit message"
|
||||||
|
input.Type(commitMessage)
|
||||||
|
input.Confirm()
|
||||||
|
|
||||||
|
assert.CommitCount(1)
|
||||||
|
assert.MatchHeadCommitMessage(Equals(commitMessage))
|
||||||
|
assert.CurrentWindowName("stagingSecondary")
|
||||||
|
},
|
||||||
|
})
|
34
pkg/integration/tests/commit/staged_without_hooks.go
Normal file
34
pkg/integration/tests/commit/staged_without_hooks.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package commit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var StagedWithoutHooks = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Staging a couple files, going in the staged files menu, unstaging a line then committing without pre-commit hooks",
|
||||||
|
ExtraCmdArgs: "",
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.
|
||||||
|
CreateFile("myfile", "myfile content\nwith a second line").
|
||||||
|
CreateFile("myfile2", "myfile2 content")
|
||||||
|
},
|
||||||
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
|
assert.CommitCount(0)
|
||||||
|
|
||||||
|
input.PrimaryAction()
|
||||||
|
input.Confirm()
|
||||||
|
input.PrimaryAction()
|
||||||
|
input.PressKeys(keys.Files.CommitChangesWithoutHook)
|
||||||
|
|
||||||
|
commitMessage := "my commit message"
|
||||||
|
input.Type(commitMessage)
|
||||||
|
input.Confirm()
|
||||||
|
|
||||||
|
assert.CommitCount(1)
|
||||||
|
assert.MatchHeadCommitMessage(Equals("WIP" + commitMessage))
|
||||||
|
assert.CurrentWindowName("stagingSecondary")
|
||||||
|
},
|
||||||
|
})
|
33
pkg/integration/tests/commit/unstaged.go
Normal file
33
pkg/integration/tests/commit/unstaged.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package commit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Unstaged = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Staging a couple files, going in the unstaged files menu, staging a line and committing",
|
||||||
|
ExtraCmdArgs: "",
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.
|
||||||
|
CreateFile("myfile", "myfile content\nwith a second line").
|
||||||
|
CreateFile("myfile2", "myfile2 content")
|
||||||
|
},
|
||||||
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
|
assert.CommitCount(0)
|
||||||
|
|
||||||
|
input.Confirm()
|
||||||
|
input.PrimaryAction()
|
||||||
|
input.PressKeys(keys.Files.CommitChanges)
|
||||||
|
|
||||||
|
commitMessage := "my commit message"
|
||||||
|
input.Type(commitMessage)
|
||||||
|
input.Confirm()
|
||||||
|
|
||||||
|
assert.CommitCount(1)
|
||||||
|
assert.MatchHeadCommitMessage(Equals(commitMessage))
|
||||||
|
assert.CurrentWindowName("staging")
|
||||||
|
},
|
||||||
|
})
|
33
pkg/integration/tests/commit/unstaged_without_hooks.go
Normal file
33
pkg/integration/tests/commit/unstaged_without_hooks.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package commit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var UnstagedWithoutHooks = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Staging a couple files, going in the unstaged files menu, staging a line and committing without pre-commit hooks",
|
||||||
|
ExtraCmdArgs: "",
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.
|
||||||
|
CreateFile("myfile", "myfile content\nwith a second line").
|
||||||
|
CreateFile("myfile2", "myfile2 content")
|
||||||
|
},
|
||||||
|
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||||
|
assert.CommitCount(0)
|
||||||
|
|
||||||
|
input.Confirm()
|
||||||
|
input.PrimaryAction()
|
||||||
|
input.PressKeys(keys.Files.CommitChangesWithoutHook)
|
||||||
|
|
||||||
|
commitMessage := "my commit message"
|
||||||
|
input.Type(commitMessage)
|
||||||
|
input.Confirm()
|
||||||
|
|
||||||
|
assert.CommitCount(1)
|
||||||
|
assert.MatchHeadCommitMessage(Equals("WIP" + commitMessage))
|
||||||
|
assert.CurrentWindowName("staging")
|
||||||
|
},
|
||||||
|
})
|
@ -36,6 +36,10 @@ var tests = []*components.IntegrationTest{
|
|||||||
cherry_pick.CherryPickConflicts,
|
cherry_pick.CherryPickConflicts,
|
||||||
commit.Commit,
|
commit.Commit,
|
||||||
commit.NewBranch,
|
commit.NewBranch,
|
||||||
|
commit.Staged,
|
||||||
|
commit.Unstaged,
|
||||||
|
commit.StagedWithoutHooks,
|
||||||
|
commit.UnstagedWithoutHooks,
|
||||||
custom_commands.Basic,
|
custom_commands.Basic,
|
||||||
custom_commands.FormPrompts,
|
custom_commands.FormPrompts,
|
||||||
custom_commands.MenuFromCommand,
|
custom_commands.MenuFromCommand,
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
my commit message
|
@ -0,0 +1 @@
|
|||||||
|
ref: refs/heads/master
|
@ -0,0 +1,12 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = false
|
||||||
|
logallrefupdates = true
|
||||||
|
[user]
|
||||||
|
email = CI@example.com
|
||||||
|
name = CI
|
||||||
|
[commit]
|
||||||
|
gpgSign = false
|
||||||
|
[protocol "file"]
|
||||||
|
allow = always
|
@ -0,0 +1 @@
|
|||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
BIN
test/integration_new/commit/staged/expected/repo/.git_keep/index
Normal file
BIN
test/integration_new/commit/staged/expected/repo/.git_keep/index
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
|||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
@ -0,0 +1 @@
|
|||||||
|
0000000000000000000000000000000000000000 a0a4dfd8937f66345c93ee7ebf5f85d53e05e9e8 CI <CI@example.com> 1669569482 +0100 commit (initial): my commit message
|
@ -0,0 +1 @@
|
|||||||
|
0000000000000000000000000000000000000000 a0a4dfd8937f66345c93ee7ebf5f85d53e05e9e8 CI <CI@example.com> 1669569482 +0100 commit (initial): my commit message
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
|||||||
|
x��M
|
||||||
|
�0]�o/H~�����%�P�GJAoo��f��D����d��(9�Xk�Y�q(`$glҕct�٨���m�i��4_�fY�8�&2!$�0Z:j����>��SW��_B�m��-�0�
|
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
a0a4dfd8937f66345c93ee7ebf5f85d53e05e9e8
|
2
test/integration_new/commit/staged/expected/repo/myfile
Normal file
2
test/integration_new/commit/staged/expected/repo/myfile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
myfile content
|
||||||
|
with a second line
|
1
test/integration_new/commit/staged/expected/repo/myfile2
Normal file
1
test/integration_new/commit/staged/expected/repo/myfile2
Normal file
@ -0,0 +1 @@
|
|||||||
|
myfile2 content
|
@ -0,0 +1 @@
|
|||||||
|
WIPmy commit message
|
@ -0,0 +1 @@
|
|||||||
|
ref: refs/heads/master
|
@ -0,0 +1,12 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = false
|
||||||
|
logallrefupdates = true
|
||||||
|
[user]
|
||||||
|
email = CI@example.com
|
||||||
|
name = CI
|
||||||
|
[commit]
|
||||||
|
gpgSign = false
|
||||||
|
[protocol "file"]
|
||||||
|
allow = always
|
@ -0,0 +1 @@
|
|||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
Binary file not shown.
@ -0,0 +1,6 @@
|
|||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
@ -0,0 +1 @@
|
|||||||
|
0000000000000000000000000000000000000000 4a33e6274dd3bc702442966e6774e7688bb7af64 CI <CI@example.com> 1669660775 +0100 commit (initial): WIPmy commit message
|
@ -0,0 +1 @@
|
|||||||
|
0000000000000000000000000000000000000000 4a33e6274dd3bc702442966e6774e7688bb7af64 CI <CI@example.com> 1669660775 +0100 commit (initial): WIPmy commit message
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
4a33e6274dd3bc702442966e6774e7688bb7af64
|
@ -0,0 +1,2 @@
|
|||||||
|
myfile content
|
||||||
|
with a second line
|
@ -0,0 +1 @@
|
|||||||
|
myfile2 content
|
@ -0,0 +1 @@
|
|||||||
|
my commit message
|
@ -0,0 +1 @@
|
|||||||
|
ref: refs/heads/master
|
@ -0,0 +1,12 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = false
|
||||||
|
logallrefupdates = true
|
||||||
|
[user]
|
||||||
|
email = CI@example.com
|
||||||
|
name = CI
|
||||||
|
[commit]
|
||||||
|
gpgSign = false
|
||||||
|
[protocol "file"]
|
||||||
|
allow = always
|
@ -0,0 +1 @@
|
|||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
Binary file not shown.
@ -0,0 +1,6 @@
|
|||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
@ -0,0 +1 @@
|
|||||||
|
0000000000000000000000000000000000000000 109e5843c76c640d7075c2897b5720f1714df776 CI <CI@example.com> 1669569750 +0100 commit (initial): my commit message
|
@ -0,0 +1 @@
|
|||||||
|
0000000000000000000000000000000000000000 109e5843c76c640d7075c2897b5720f1714df776 CI <CI@example.com> 1669569750 +0100 commit (initial): my commit message
|
Binary file not shown.
@ -0,0 +1,2 @@
|
|||||||
|
x��K
|
||||||
|
�0@]��$ ��D��z�L2~�!�F��[�n��J3�wH������*�5�K�IQt1�DA�<V�.���-0�p�泾�=z(�N�Rb����{��m��O��~ ��k���m�1|
|
@ -0,0 +1 @@
|
|||||||
|
x+)JMU06a040031QȭL��Ie`x�f��vYR��j�\�~�]�t��
|
@ -0,0 +1 @@
|
|||||||
|
109e5843c76c640d7075c2897b5720f1714df776
|
@ -0,0 +1,2 @@
|
|||||||
|
myfile content
|
||||||
|
with a second line
|
@ -0,0 +1 @@
|
|||||||
|
myfile2 content
|
@ -0,0 +1 @@
|
|||||||
|
WIPmy commit message
|
@ -0,0 +1 @@
|
|||||||
|
ref: refs/heads/master
|
@ -0,0 +1,12 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = false
|
||||||
|
logallrefupdates = true
|
||||||
|
[user]
|
||||||
|
email = CI@example.com
|
||||||
|
name = CI
|
||||||
|
[commit]
|
||||||
|
gpgSign = false
|
||||||
|
[protocol "file"]
|
||||||
|
allow = always
|
@ -0,0 +1 @@
|
|||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
Binary file not shown.
@ -0,0 +1,6 @@
|
|||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
@ -0,0 +1 @@
|
|||||||
|
0000000000000000000000000000000000000000 ebc03af0e92eb50f1ab1dec0697880ed9da9b02d CI <CI@example.com> 1669660788 +0100 commit (initial): WIPmy commit message
|
@ -0,0 +1 @@
|
|||||||
|
0000000000000000000000000000000000000000 ebc03af0e92eb50f1ab1dec0697880ed9da9b02d CI <CI@example.com> 1669660788 +0100 commit (initial): WIPmy commit message
|
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
x+)JMU06a040031QȭL��Ie`x�f��vYR��j�\�~�]�t��
|
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
ebc03af0e92eb50f1ab1dec0697880ed9da9b02d
|
@ -0,0 +1,2 @@
|
|||||||
|
myfile content
|
||||||
|
with a second line
|
@ -0,0 +1 @@
|
|||||||
|
myfile2 content
|
Reference in New Issue
Block a user