mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-08-06 22:33:07 +02:00
Fix performance regression on startup in repos with many tags (#4777)
- **PR Description** In #4663 we added information in the tags panel about the selected tag (whether it's annotated etc). Unfortunately this introduced a performance regression in repositories with many tags, so revert this and implement the feature in a slightly different way to avoid the performance hit. Fixes #4770.
This commit is contained in:
@ -1,6 +1,8 @@
|
|||||||
package git_commands
|
package git_commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
)
|
)
|
||||||
@ -74,3 +76,13 @@ func (self *TagCommands) ShowAnnotationInfo(tagName string) (string, error) {
|
|||||||
|
|
||||||
return self.cmd.New(cmdArgs).RunWithOutput()
|
return self.cmd.New(cmdArgs).RunWithOutput()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *TagCommands) IsTagAnnotated(tagName string) (bool, error) {
|
||||||
|
cmdArgs := NewGitCmd("cat-file").
|
||||||
|
Arg("-t").
|
||||||
|
Arg("refs/tags/" + tagName).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
output, err := self.cmd.New(cmdArgs).RunWithOutput()
|
||||||
|
return strings.TrimSpace(output) == "tag", err
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package git_commands
|
package git_commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"regexp"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
@ -26,13 +26,9 @@ func NewTagLoader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *TagLoader) GetTags() ([]*models.Tag, error) {
|
func (self *TagLoader) GetTags() ([]*models.Tag, error) {
|
||||||
// get tags, sorted by creation date (descending)
|
// get remote branches, sorted by creation date (descending)
|
||||||
// see: https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---sortltkeygt
|
// see: https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---sortltkeygt
|
||||||
cmdArgs := NewGitCmd("for-each-ref").
|
cmdArgs := NewGitCmd("tag").Arg("--list", "-n", "--sort=-creatordate").ToArgv()
|
||||||
Arg("--sort=-creatordate").
|
|
||||||
Arg("--format=%(refname)%00%(objecttype)%00%(contents:subject)").
|
|
||||||
Arg("refs/tags").
|
|
||||||
ToArgv()
|
|
||||||
tagsOutput, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
tagsOutput, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -40,20 +36,20 @@ func (self *TagLoader) GetTags() ([]*models.Tag, error) {
|
|||||||
|
|
||||||
split := utils.SplitLines(tagsOutput)
|
split := utils.SplitLines(tagsOutput)
|
||||||
|
|
||||||
tags := lo.FilterMap(split, func(line string, _ int) (*models.Tag, bool) {
|
lineRegex := regexp.MustCompile(`^([^\s]+)(\s+)?(.*)$`)
|
||||||
fields := strings.SplitN(line, "\x00", 3)
|
|
||||||
if len(fields) != 3 {
|
tags := lo.Map(split, func(line string, _ int) *models.Tag {
|
||||||
return nil, false
|
matches := lineRegex.FindStringSubmatch(line)
|
||||||
|
tagName := matches[1]
|
||||||
|
message := ""
|
||||||
|
if len(matches) > 3 {
|
||||||
|
message = matches[3]
|
||||||
}
|
}
|
||||||
tagName := fields[0]
|
|
||||||
objectType := fields[1]
|
|
||||||
message := fields[2]
|
|
||||||
|
|
||||||
return &models.Tag{
|
return &models.Tag{
|
||||||
Name: strings.TrimPrefix(tagName, "refs/tags/"),
|
Name: tagName,
|
||||||
Message: message,
|
Message: message,
|
||||||
IsAnnotated: objectType == "tag",
|
}
|
||||||
}, true
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return tags, nil
|
return tags, nil
|
||||||
|
@ -9,9 +9,10 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tagsOutput = "refs/tags/tag1\x00tag\x00this is my message\n" +
|
const tagsOutput = `tag1 this is my message
|
||||||
"refs/tags/tag2\x00commit\x00\n" +
|
tag2
|
||||||
"refs/tags/tag3\x00tag\x00this is my other message\n"
|
tag3 this is my other message
|
||||||
|
`
|
||||||
|
|
||||||
func TestGetTags(t *testing.T) {
|
func TestGetTags(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
@ -25,18 +26,18 @@ func TestGetTags(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testName: "should return no tags if there are none",
|
testName: "should return no tags if there are none",
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"for-each-ref", "--sort=-creatordate", "--format=%(refname)%00%(objecttype)%00%(contents:subject)", "refs/tags"}, "", nil),
|
ExpectGitArgs([]string{"tag", "--list", "-n", "--sort=-creatordate"}, "", nil),
|
||||||
expectedTags: []*models.Tag{},
|
expectedTags: []*models.Tag{},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "should return tags if present",
|
testName: "should return tags if present",
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"for-each-ref", "--sort=-creatordate", "--format=%(refname)%00%(objecttype)%00%(contents:subject)", "refs/tags"}, tagsOutput, nil),
|
ExpectGitArgs([]string{"tag", "--list", "-n", "--sort=-creatordate"}, tagsOutput, nil),
|
||||||
expectedTags: []*models.Tag{
|
expectedTags: []*models.Tag{
|
||||||
{Name: "tag1", Message: "this is my message", IsAnnotated: true},
|
{Name: "tag1", Message: "this is my message"},
|
||||||
{Name: "tag2", Message: "", IsAnnotated: false},
|
{Name: "tag2", Message: ""},
|
||||||
{Name: "tag3", Message: "this is my other message", IsAnnotated: true},
|
{Name: "tag3", Message: "this is my other message"},
|
||||||
},
|
},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
},
|
},
|
||||||
|
@ -3,13 +3,9 @@ package models
|
|||||||
// Tag : A git tag
|
// Tag : A git tag
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// this is either the first line of the message of an annotated tag, or the
|
// this is either the first line of the message of an annotated tag, or the
|
||||||
// first line of a commit message for a lightweight tag
|
// first line of a commit message for a lightweight tag
|
||||||
Message string
|
Message string
|
||||||
|
|
||||||
// true if this is an annotated tag, false if it's a lightweight tag
|
|
||||||
IsAnnotated bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tag) FullRefName() string {
|
func (t *Tag) FullRefName() string {
|
||||||
|
@ -117,7 +117,12 @@ func (self *TagsController) GetOnRenderToMain() func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *TagsController) getTagInfo(tag *models.Tag) string {
|
func (self *TagsController) getTagInfo(tag *models.Tag) string {
|
||||||
if tag.IsAnnotated {
|
tagIsAnnotated, err := self.c.Git().Tag.IsTagAnnotated(tag.Name)
|
||||||
|
if err != nil {
|
||||||
|
self.c.Log.Warnf("Error checking if tag is annotated: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tagIsAnnotated {
|
||||||
info := fmt.Sprintf("%s: %s", self.c.Tr.AnnotatedTag, style.AttrBold.Sprint(style.FgYellow.Sprint(tag.Name)))
|
info := fmt.Sprintf("%s: %s", self.c.Tr.AnnotatedTag, style.AttrBold.Sprint(style.FgYellow.Sprint(tag.Name)))
|
||||||
output, err := self.c.Git().Tag.ShowAnnotationInfo(tag.Name)
|
output, err := self.c.Git().Tag.ShowAnnotationInfo(tag.Name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -32,6 +32,18 @@ var CrudAnnotated = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Lines(
|
Lines(
|
||||||
MatchesRegexp(`new-tag.*message`).IsSelected(),
|
MatchesRegexp(`new-tag.*message`).IsSelected(),
|
||||||
).
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Main().ContainsLines(
|
||||||
|
Equals("Annotated tag: new-tag"),
|
||||||
|
Equals(""),
|
||||||
|
Contains("Tagger:"),
|
||||||
|
Contains("TaggerDate:"),
|
||||||
|
Equals(""),
|
||||||
|
Equals("message"),
|
||||||
|
Equals(""),
|
||||||
|
Equals("---"),
|
||||||
|
)
|
||||||
|
}).
|
||||||
Press(keys.Universal.Push).
|
Press(keys.Universal.Push).
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectPopup().Prompt().
|
t.ExpectPopup().Prompt().
|
||||||
|
@ -28,6 +28,13 @@ var CrudLightweight = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Lines(
|
Lines(
|
||||||
MatchesRegexp(`new-tag.*initial commit`).IsSelected(),
|
MatchesRegexp(`new-tag.*initial commit`).IsSelected(),
|
||||||
).
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Main().ContainsLines(
|
||||||
|
Equals("Lightweight tag: new-tag"),
|
||||||
|
Equals(""),
|
||||||
|
Equals("---"),
|
||||||
|
)
|
||||||
|
}).
|
||||||
PressEnter().
|
PressEnter().
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
// view the commits of the tag
|
// view the commits of the tag
|
||||||
|
Reference in New Issue
Block a user