diff --git a/pkg/commands/git_commands/tag_loader.go b/pkg/commands/git_commands/tag_loader.go index bd05fe4b4..1d51c5e5c 100644 --- a/pkg/commands/git_commands/tag_loader.go +++ b/pkg/commands/git_commands/tag_loader.go @@ -1,7 +1,7 @@ package git_commands import ( - "regexp" + "strings" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" @@ -26,9 +26,13 @@ func NewTagLoader( } func (self *TagLoader) GetTags() ([]*models.Tag, error) { - // get remote branches, sorted by creation date (descending) + // get tags, sorted by creation date (descending) // see: https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---sortltkeygt - cmdArgs := NewGitCmd("tag").Arg("--list", "-n", "--sort=-creatordate").ToArgv() + cmdArgs := NewGitCmd("for-each-ref"). + Arg("--sort=-creatordate"). + Arg("--format=%(refname)%00%(objecttype)%00%(contents:subject)"). + Arg("refs/tags"). + ToArgv() tagsOutput, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput() if err != nil { return nil, err @@ -36,20 +40,20 @@ func (self *TagLoader) GetTags() ([]*models.Tag, error) { split := utils.SplitLines(tagsOutput) - lineRegex := regexp.MustCompile(`^([^\s]+)(\s+)?(.*)$`) - - tags := lo.Map(split, func(line string, _ int) *models.Tag { - matches := lineRegex.FindStringSubmatch(line) - tagName := matches[1] - message := "" - if len(matches) > 3 { - message = matches[3] + tags := lo.FilterMap(split, func(line string, _ int) (*models.Tag, bool) { + fields := strings.SplitN(line, "\x00", 3) + if len(fields) != 3 { + return nil, false } + tagName := fields[0] + objectType := fields[1] + message := fields[2] return &models.Tag{ - Name: tagName, - Message: message, - } + Name: strings.TrimPrefix(tagName, "refs/tags/"), + Message: message, + IsAnnotated: objectType == "tag", + }, true }) return tags, nil diff --git a/pkg/commands/git_commands/tag_loader_test.go b/pkg/commands/git_commands/tag_loader_test.go index e8f19fcd4..a56aa34c7 100644 --- a/pkg/commands/git_commands/tag_loader_test.go +++ b/pkg/commands/git_commands/tag_loader_test.go @@ -9,10 +9,9 @@ import ( "github.com/stretchr/testify/assert" ) -const tagsOutput = `tag1 this is my message -tag2 -tag3 this is my other message -` +const tagsOutput = "refs/tags/tag1\x00tag\x00this is my message\n" + + "refs/tags/tag2\x00commit\x00\n" + + "refs/tags/tag3\x00tag\x00this is my other message\n" func TestGetTags(t *testing.T) { type scenario struct { @@ -26,18 +25,18 @@ func TestGetTags(t *testing.T) { { testName: "should return no tags if there are none", runner: oscommands.NewFakeRunner(t). - ExpectGitArgs([]string{"tag", "--list", "-n", "--sort=-creatordate"}, "", nil), + ExpectGitArgs([]string{"for-each-ref", "--sort=-creatordate", "--format=%(refname)%00%(objecttype)%00%(contents:subject)", "refs/tags"}, "", nil), expectedTags: []*models.Tag{}, expectedError: nil, }, { testName: "should return tags if present", runner: oscommands.NewFakeRunner(t). - ExpectGitArgs([]string{"tag", "--list", "-n", "--sort=-creatordate"}, tagsOutput, nil), + ExpectGitArgs([]string{"for-each-ref", "--sort=-creatordate", "--format=%(refname)%00%(objecttype)%00%(contents:subject)", "refs/tags"}, tagsOutput, nil), expectedTags: []*models.Tag{ - {Name: "tag1", Message: "this is my message"}, - {Name: "tag2", Message: ""}, - {Name: "tag3", Message: "this is my other message"}, + {Name: "tag1", Message: "this is my message", IsAnnotated: true}, + {Name: "tag2", Message: "", IsAnnotated: false}, + {Name: "tag3", Message: "this is my other message", IsAnnotated: true}, }, expectedError: nil, }, diff --git a/pkg/commands/models/tag.go b/pkg/commands/models/tag.go index 876e2cd77..389083c94 100644 --- a/pkg/commands/models/tag.go +++ b/pkg/commands/models/tag.go @@ -3,9 +3,13 @@ package models // Tag : A git tag type Tag struct { Name string + // 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 Message string + + // true if this is an annotated tag, false if it's a lightweight tag + IsAnnotated bool } func (t *Tag) FullRefName() string {