Log the hash of dropped stashes (#4850)

### PR Description

If you dropped/popped a stash accidentally, the logged hash can help
recover it more easily.

Supersedes #4847.
This commit is contained in:
Stefan Haller 2025-08-26 14:02:43 +02:00 committed by GitHub
commit be0d7a6e73
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 39 additions and 14 deletions

View file

@ -32,7 +32,7 @@ func (self *StashLoader) GetStashEntries(filterPath string) []*models.StashEntry
return self.getUnfilteredStashEntries()
}
cmdArgs := NewGitCmd("stash").Arg("list", "--name-only", "--pretty=%gd:%ct|%gs").ToArgv()
cmdArgs := NewGitCmd("stash").Arg("list", "--name-only", "--pretty=%gd:%H|%ct|%gs").ToArgv()
rawString, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
if err != nil {
return self.getUnfilteredStashEntries()
@ -66,7 +66,7 @@ outer:
}
func (self *StashLoader) getUnfilteredStashEntries() []*models.StashEntry {
cmdArgs := NewGitCmd("stash").Arg("list", "-z", "--pretty=%ct|%gs").ToArgv()
cmdArgs := NewGitCmd("stash").Arg("list", "-z", "--pretty=%H|%ct|%gs").ToArgv()
rawString, _ := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
return lo.Map(utils.SplitNul(rawString), func(line string, index int) *models.StashEntry {
@ -80,6 +80,12 @@ func stashEntryFromLine(line string, index int) *models.StashEntry {
Index: index,
}
hash, line, ok := strings.Cut(line, "|")
if !ok {
return model
}
model.Hash = hash
tstr, msg, ok := strings.Cut(line, "|")
if !ok {
return model

View file

@ -1,7 +1,9 @@
package git_commands
import (
"fmt"
"testing"
"time"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
@ -17,30 +19,38 @@ func TestGetStashEntries(t *testing.T) {
expectedStashEntries []*models.StashEntry
}
hoursAgo := time.Now().Unix() - 3*3600 - 1800
daysAgo := time.Now().Unix() - 3*3600*24 - 3600*12
scenarios := []scenario{
{
"No stash entries found",
"",
oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%ct|%gs"}, "", nil),
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%H|%ct|%gs"}, "", nil),
[]*models.StashEntry{},
},
{
"Several stash entries found",
"",
oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%ct|%gs"},
"WIP on add-pkg-commands-test: 55c6af2 increase parallel build\x00WIP on master: bb86a3f update github template\x00",
nil,
),
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%H|%ct|%gs"},
fmt.Sprintf("fa1afe1|%d|WIP on add-pkg-commands-test: 55c6af2 increase parallel build\x00deadbeef|%d|WIP on master: bb86a3f update github template\x00",
hoursAgo,
daysAgo,
), nil),
[]*models.StashEntry{
{
Index: 0,
Name: "WIP on add-pkg-commands-test: 55c6af2 increase parallel build",
Index: 0,
Name: "WIP on add-pkg-commands-test: 55c6af2 increase parallel build",
Recency: "3h",
Hash: "fa1afe1",
},
{
Index: 1,
Name: "WIP on master: bb86a3f update github template",
Index: 1,
Name: "WIP on master: bb86a3f update github template",
Recency: "3d",
Hash: "deadbeef",
},
},
},

View file

@ -7,6 +7,7 @@ type StashEntry struct {
Index int
Recency string
Name string
Hash string
}
func (s *StashEntry) FullRefName() string {

View file

@ -112,7 +112,7 @@ func (self *StashController) handleStashApply(stashEntry *models.StashEntry) err
Title: self.c.Tr.StashApply,
Prompt: self.c.Tr.SureApplyStashEntry,
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.Stash)
self.c.LogAction(self.c.Tr.Actions.ApplyStash)
err := self.c.Git().Stash.Apply(stashEntry.Index)
self.postStashRefresh()
if err != nil {
@ -128,7 +128,8 @@ func (self *StashController) handleStashApply(stashEntry *models.StashEntry) err
func (self *StashController) handleStashPop(stashEntry *models.StashEntry) error {
pop := func() error {
self.c.LogAction(self.c.Tr.Actions.Stash)
self.c.LogAction(self.c.Tr.Actions.PopStash)
self.c.LogCommand("Popping stash "+stashEntry.Hash, false)
err := self.c.Git().Stash.Pop(stashEntry.Index)
self.postStashRefresh()
if err != nil {
@ -160,8 +161,9 @@ func (self *StashController) handleStashDrop(stashEntries []*models.StashEntry)
Title: self.c.Tr.StashDrop,
Prompt: self.c.Tr.SureDropStashEntry,
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.Stash)
self.c.LogAction(self.c.Tr.Actions.DropStash)
for i := len(stashEntries) - 1; i >= 0; i-- {
self.c.LogCommand("Dropping stash "+stashEntries[i].Hash, false)
err := self.c.Git().Stash.Drop(stashEntries[i].Index)
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
if err != nil {

View file

@ -1011,6 +1011,9 @@ type Actions struct {
UpdateRemote string
ApplyPatch string
Stash string
PopStash string
ApplyStash string
DropStash string
RenameStash string
RemoveSubmodule string
ResetSubmodule string
@ -2050,6 +2053,9 @@ func EnglishTranslationSet() *TranslationSet {
UpdateRemote: "Update remote",
ApplyPatch: "Apply patch",
Stash: "Stash",
PopStash: "Pop stash",
ApplyStash: "Apply stash",
DropStash: "Drop stash",
RenameStash: "Rename stash",
RemoveSubmodule: "Remove submodule",
ResetSubmodule: "Reset submodule",