mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-28 16:02:01 +03:00
feat: add rename stash
This commit is contained in:
@ -223,6 +223,7 @@ keybinding:
|
||||
viewBisectOptions: 'b'
|
||||
stash:
|
||||
popStash: 'g'
|
||||
renameStash: 'r'
|
||||
commitFiles:
|
||||
checkoutCommitFile: 'c'
|
||||
main:
|
||||
|
@ -238,6 +238,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
||||
<kbd>g</kbd>: pop
|
||||
<kbd>d</kbd>: drop
|
||||
<kbd>n</kbd>: new branch
|
||||
<kbd>r</kbd>: rename stash
|
||||
<kbd>enter</kbd>: view selected item's files
|
||||
</pre>
|
||||
|
||||
|
@ -48,6 +48,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
||||
<kbd>g</kbd>: pop
|
||||
<kbd>d</kbd>: drop
|
||||
<kbd>n</kbd>: 新しいブランチを作成
|
||||
<kbd>r</kbd>: Stashを変更
|
||||
<kbd>enter</kbd>: view selected item's files
|
||||
</pre>
|
||||
|
||||
|
@ -63,6 +63,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
||||
<kbd>g</kbd>: pop
|
||||
<kbd>d</kbd>: drop
|
||||
<kbd>n</kbd>: 새 브랜치 생성
|
||||
<kbd>r</kbd>: rename stash
|
||||
<kbd>enter</kbd>: view selected item's files
|
||||
</pre>
|
||||
|
||||
|
@ -238,6 +238,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
||||
<kbd>g</kbd>: pop
|
||||
<kbd>d</kbd>: laten vallen
|
||||
<kbd>n</kbd>: nieuwe branch
|
||||
<kbd>r</kbd>: rename stash
|
||||
<kbd>enter</kbd>: bekijk gecommite bestanden
|
||||
</pre>
|
||||
|
||||
|
@ -231,6 +231,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
||||
<kbd>g</kbd>: wyciągnij
|
||||
<kbd>d</kbd>: porzuć
|
||||
<kbd>n</kbd>: nowa gałąź
|
||||
<kbd>r</kbd>: rename stash
|
||||
<kbd>enter</kbd>: przeglądaj pliki commita
|
||||
</pre>
|
||||
|
||||
|
@ -264,6 +264,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
||||
<kbd>g</kbd>: 应用并删除
|
||||
<kbd>d</kbd>: 删除
|
||||
<kbd>n</kbd>: 新分支
|
||||
<kbd>r</kbd>: rename stash
|
||||
<kbd>enter</kbd>: 查看提交的文件
|
||||
</pre>
|
||||
|
||||
|
@ -2,6 +2,7 @@ package git_commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/loaders"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||
@ -29,8 +30,9 @@ func (self *StashCommands) DropNewest() error {
|
||||
return self.cmd.New("git stash drop").Run()
|
||||
}
|
||||
|
||||
func (self *StashCommands) Drop(index int) error {
|
||||
return self.cmd.New(fmt.Sprintf("git stash drop stash@{%d}", index)).Run()
|
||||
func (self *StashCommands) Drop(index int) (string, error) {
|
||||
output, _, err := self.cmd.New(fmt.Sprintf("git stash drop stash@{%d}", index)).RunWithOutputs()
|
||||
return output, err
|
||||
}
|
||||
|
||||
func (self *StashCommands) Pop(index int) error {
|
||||
@ -46,6 +48,14 @@ func (self *StashCommands) Save(message string) error {
|
||||
return self.cmd.New("git stash save " + self.cmd.Quote(message)).Run()
|
||||
}
|
||||
|
||||
func (self *StashCommands) Store(sha string, message string) error {
|
||||
trimmedMessage := strings.Trim(message, " \t")
|
||||
if len(trimmedMessage) > 0 {
|
||||
return self.cmd.New(fmt.Sprintf("git stash store %s -m %s", self.cmd.Quote(sha), self.cmd.Quote(trimmedMessage))).Run()
|
||||
}
|
||||
return self.cmd.New(fmt.Sprintf("git stash store %s", self.cmd.Quote(sha))).Run()
|
||||
}
|
||||
|
||||
func (self *StashCommands) ShowStashEntryCmdObj(index int) oscommands.ICmdObj {
|
||||
cmdStr := fmt.Sprintf("git stash show -p --stat --color=%s --unified=%d stash@{%d}", self.UserConfig.Git.Paging.ColorArg, self.UserConfig.Git.DiffContextSize, index)
|
||||
|
||||
|
@ -10,10 +10,12 @@ import (
|
||||
|
||||
func TestStashDrop(t *testing.T) {
|
||||
runner := oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"stash", "drop", "stash@{1}"}, "", nil)
|
||||
ExpectGitArgs([]string{"stash", "drop", "stash@{1}"}, "Dropped refs/stash@{1} (98e9cca532c37c766107093010c72e26f2c24c04)", nil)
|
||||
instance := buildStashCommands(commonDeps{runner: runner})
|
||||
|
||||
assert.NoError(t, instance.Drop(1))
|
||||
output, err := instance.Drop(1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Dropped refs/stash@{1} (98e9cca532c37c766107093010c72e26f2c24c04)", output)
|
||||
runner.CheckForMissingCalls()
|
||||
}
|
||||
|
||||
@ -44,6 +46,48 @@ func TestStashSave(t *testing.T) {
|
||||
runner.CheckForMissingCalls()
|
||||
}
|
||||
|
||||
func TestStashStore(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
sha string
|
||||
message string
|
||||
expected []string
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
testName: "Non-empty message",
|
||||
sha: "0123456789abcdef",
|
||||
message: "New stash name",
|
||||
expected: []string{"stash", "store", "0123456789abcdef", "-m", "New stash name"},
|
||||
},
|
||||
{
|
||||
testName: "Empty message",
|
||||
sha: "0123456789abcdef",
|
||||
message: "",
|
||||
expected: []string{"stash", "store", "0123456789abcdef"},
|
||||
},
|
||||
{
|
||||
testName: "Space message",
|
||||
sha: "0123456789abcdef",
|
||||
message: " ",
|
||||
expected: []string{"stash", "store", "0123456789abcdef"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range scenarios {
|
||||
s := s
|
||||
t.Run(s.testName, func(t *testing.T) {
|
||||
runner := oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs(s.expected, "", nil)
|
||||
instance := buildStashCommands(commonDeps{runner: runner})
|
||||
|
||||
assert.NoError(t, instance.Store(s.sha, s.message))
|
||||
runner.CheckForMissingCalls()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStashStashEntryCmdObj(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
|
@ -266,6 +266,7 @@ type KeybindingCommitsConfig struct {
|
||||
|
||||
type KeybindingStashConfig struct {
|
||||
PopStash string `yaml:"popStash"`
|
||||
RenameStash string `yaml:"renameStash"`
|
||||
}
|
||||
|
||||
type KeybindingCommitFilesConfig struct {
|
||||
@ -548,6 +549,7 @@ func GetDefaultConfig() *UserConfig {
|
||||
},
|
||||
Stash: KeybindingStashConfig{
|
||||
PopStash: "g",
|
||||
RenameStash: "r",
|
||||
},
|
||||
CommitFiles: KeybindingCommitFilesConfig{
|
||||
CheckoutCommitFile: "c",
|
||||
|
@ -1,9 +1,12 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
type StashController struct {
|
||||
@ -44,6 +47,11 @@ func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
Handler: self.checkSelected(self.handleNewBranchOffStashEntry),
|
||||
Description: self.c.Tr.LcNewBranch,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Stash.RenameStash),
|
||||
Handler: self.checkSelected(self.handleRenameStashEntry),
|
||||
Description: self.c.Tr.LcRenameStash,
|
||||
},
|
||||
}
|
||||
|
||||
return bindings
|
||||
@ -122,7 +130,7 @@ func (self *StashController) handleStashDrop(stashEntry *models.StashEntry) erro
|
||||
Prompt: self.c.Tr.SureDropStashEntry,
|
||||
HandleConfirm: func() error {
|
||||
self.c.LogAction(self.c.Tr.Actions.Stash)
|
||||
err := self.git.Stash.Drop(stashEntry.Index)
|
||||
_, err := self.git.Stash.Drop(stashEntry.Index)
|
||||
_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
|
||||
if err != nil {
|
||||
return self.c.Error(err)
|
||||
@ -139,3 +147,38 @@ func (self *StashController) postStashRefresh() error {
|
||||
func (self *StashController) handleNewBranchOffStashEntry(stashEntry *models.StashEntry) error {
|
||||
return self.helpers.Refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "")
|
||||
}
|
||||
|
||||
func (self *StashController) handleRenameStashEntry(stashEntry *models.StashEntry) error {
|
||||
message := utils.ResolvePlaceholderString(
|
||||
self.c.Tr.RenameStashPrompt,
|
||||
map[string]string{
|
||||
"stashName": stashEntry.RefName(),
|
||||
},
|
||||
)
|
||||
|
||||
return self.c.Prompt(types.PromptOpts{
|
||||
Title: message,
|
||||
InitialContent: stashEntry.Name,
|
||||
HandleConfirm: func(response string) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.RenameStash)
|
||||
output, err := self.git.Stash.Drop(stashEntry.Index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stashShaPattern := regexp.MustCompile(`\(([0-9a-f]+)\)`)
|
||||
matches := stashShaPattern.FindStringSubmatch(output)
|
||||
stashSha := ""
|
||||
if len(matches) > 1 {
|
||||
stashSha = matches[1]
|
||||
}
|
||||
|
||||
err = self.git.Stash.Store(stashSha, response)
|
||||
_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -139,6 +139,8 @@ func chineseTranslationSet() TranslationSet {
|
||||
SureApplyStashEntry: "您确定要应用此贮藏条目?",
|
||||
NoTrackedStagedFilesStash: "没有可以贮藏的已跟踪/暂存文件",
|
||||
StashChanges: "贮藏更改",
|
||||
LcRenameStash: "rename stash",
|
||||
RenameStashPrompt: "Rename stash: {{.stashName}}",
|
||||
OpenConfig: "打开配置文件",
|
||||
EditConfig: "编辑配置文件",
|
||||
ForcePush: "强制推送",
|
||||
@ -530,6 +532,7 @@ func chineseTranslationSet() TranslationSet {
|
||||
UpdateRemote: "更新远程",
|
||||
ApplyPatch: "应用补丁",
|
||||
Stash: "贮藏 (Stash)",
|
||||
RenameStash: "Rename stash",
|
||||
RemoveSubmodule: "删除子模块",
|
||||
ResetSubmodule: "重置子模块",
|
||||
AddSubmodule: "添加子模块",
|
||||
|
@ -105,6 +105,8 @@ func dutchTranslationSet() TranslationSet {
|
||||
SureApplyStashEntry: "Weet je zeker dat je deze stash entry wil toepassen?",
|
||||
NoTrackedStagedFilesStash: "Je hebt geen tracked/staged bestanden om te laten stashen",
|
||||
StashChanges: "Stash veranderingen",
|
||||
LcRenameStash: "rename stash",
|
||||
RenameStashPrompt: "Rename stash: {{.stashName}}",
|
||||
NoChangedFiles: "Geen veranderde bestanden",
|
||||
OpenConfig: "open config bestand",
|
||||
EditConfig: "verander config bestand",
|
||||
|
@ -128,6 +128,8 @@ type TranslationSet struct {
|
||||
NoTrackedStagedFilesStash string
|
||||
NoFilesToStash string
|
||||
StashChanges string
|
||||
LcRenameStash string
|
||||
RenameStashPrompt string
|
||||
OpenConfig string
|
||||
EditConfig string
|
||||
ForcePush string
|
||||
@ -601,6 +603,7 @@ type Actions struct {
|
||||
UpdateRemote string
|
||||
ApplyPatch string
|
||||
Stash string
|
||||
RenameStash string
|
||||
RemoveSubmodule string
|
||||
ResetSubmodule string
|
||||
AddSubmodule string
|
||||
@ -769,6 +772,8 @@ func EnglishTranslationSet() TranslationSet {
|
||||
NoTrackedStagedFilesStash: "You have no tracked/staged files to stash",
|
||||
NoFilesToStash: "You have no files to stash",
|
||||
StashChanges: "Stash changes",
|
||||
LcRenameStash: "rename stash",
|
||||
RenameStashPrompt: "Rename stash: {{.stashName}}",
|
||||
OpenConfig: "open config file",
|
||||
EditConfig: "edit config file",
|
||||
ForcePush: "Force push",
|
||||
@ -1226,6 +1231,7 @@ func EnglishTranslationSet() TranslationSet {
|
||||
UpdateRemote: "Update remote",
|
||||
ApplyPatch: "Apply patch",
|
||||
Stash: "Stash",
|
||||
RenameStash: "Rename stash",
|
||||
RemoveSubmodule: "Remove submodule",
|
||||
ResetSubmodule: "Reset submodule",
|
||||
AddSubmodule: "Add submodule",
|
||||
|
@ -130,6 +130,8 @@ func japaneseTranslationSet() TranslationSet {
|
||||
SureApplyStashEntry: "Stashを適用します。よろしいですか?",
|
||||
// NoTrackedStagedFilesStash: "You have no tracked/staged files to stash",
|
||||
StashChanges: "変更をStash",
|
||||
LcRenameStash: "Stashを変更",
|
||||
RenameStashPrompt: "Stash名を変更: {{.stashName}}",
|
||||
OpenConfig: "設定ファイルを開く",
|
||||
EditConfig: "設定ファイルを編集",
|
||||
ForcePush: "Force push",
|
||||
@ -556,6 +558,7 @@ func japaneseTranslationSet() TranslationSet {
|
||||
UpdateRemote: "リモートを更新",
|
||||
ApplyPatch: "パッチを適用",
|
||||
Stash: "Stash",
|
||||
RenameStash: "Stash名を変更",
|
||||
RemoveSubmodule: "サブモジュールを削除",
|
||||
ResetSubmodule: "サブモジュールをリセット",
|
||||
AddSubmodule: "サブモジュールを追加",
|
||||
|
@ -131,6 +131,8 @@ func koreanTranslationSet() TranslationSet {
|
||||
SureApplyStashEntry: "정말로 Stash를 적용하시겠습니까?",
|
||||
NoTrackedStagedFilesStash: "You have no tracked/staged files to stash",
|
||||
StashChanges: "변경을 Stash",
|
||||
LcRenameStash: "rename stash",
|
||||
RenameStashPrompt: "Rename stash: {{.stashName}}",
|
||||
OpenConfig: "설정 파일 열기",
|
||||
EditConfig: "설정 파일 수정",
|
||||
ForcePush: "강제 푸시",
|
||||
@ -561,6 +563,7 @@ func koreanTranslationSet() TranslationSet {
|
||||
UpdateRemote: "Update remote",
|
||||
ApplyPatch: "Apply patch",
|
||||
Stash: "Stash",
|
||||
RenameStash: "Rename stash",
|
||||
RemoveSubmodule: "서브모듈 삭제",
|
||||
ResetSubmodule: "서브모듈 Reset",
|
||||
AddSubmodule: "서브모듈 추가",
|
||||
|
@ -83,6 +83,8 @@ func polishTranslationSet() TranslationSet {
|
||||
SureDropStashEntry: "Jesteś pewny, że chcesz porzucić tę pozycję w schowku?",
|
||||
NoTrackedStagedFilesStash: "Nie masz śledzonych/zatwierdzonych plików do przechowania",
|
||||
StashChanges: "Przechowaj zmiany",
|
||||
LcRenameStash: "rename stash",
|
||||
RenameStashPrompt: "Rename stash: {{.stashName}}",
|
||||
OpenConfig: "otwórz konfigurację",
|
||||
EditConfig: "edytuj konfigurację",
|
||||
ForcePush: "Wymuś wysłanie",
|
||||
|
Reference in New Issue
Block a user