Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

List branches and tags in one for-each-ref

34cbc99f43af6f8f49d76f9221cb7afebe40db0d · Keenan Nemetz · 10d ago · parent 5cecc618

List branches and tags in one for-each-ref

The code browser and the compare page asked git for branch names and tag
names separately. They are the same ref listing under two prefixes, so
one `for-each-ref` answers both.

The listing carries each ref's creation time, which is what lets the tag
picker stay newest-first after the lists are merged: branches are sorted
by name, tags by time with the name breaking a tie.

The code page drops from 45 git invocations to 44 on a repository with a
handful of refs, and one process per page on every repository.

server/web/codebrowser.go +26−19

@@ -120,30 +120,37 @@ func (w *Web) codeShell(r *http.Request, m *repo.Meta, ref, commit, active strin
120 120 v.Count, _ = g.CountCommits(commit)
121 121 v.Tree, v.TreeTruncated = buildFileTree(g, commit, active)
122 122 }
123 branches, _ := g.ListRefs("refs/heads/")
124 names := make([]string, 0, len(branches))
125 for k := range branches {
126 names = append(names, strings.TrimPrefix(k, "refs/heads/"))
127 }
128 sort.Strings(names)
129 v.Branches = names
130 for _, name := range names {
131 if name == ref {
132 v.OnBranch = true
133 break
134 }
135 }
136 123 // Tags share the ref picker's target: a tag names a commit, so browsing a
137 // tag is the same page as browsing a branch.
138 if tags, err := g.Tags(); err == nil {
139 v.Tags = make([]string, 0, len(tags))
140 for _, tag := range tags {
141 v.Tags = append(v.Tags, tag.Name)
142 if tag.Name == ref {
124 // tag is the same page as browsing a branch. One listing answers both pickers;
125 // branches stay alphabetical and tags stay newest first.
126 refs, _ := g.Refs("refs/heads/", "refs/tags/")
127 var tags []git.RefEntry
128 for _, rf := range refs {
129 switch {
130 case strings.HasPrefix(rf.Name, "refs/heads/"):
131 name := strings.TrimPrefix(rf.Name, "refs/heads/")
132 v.Branches = append(v.Branches, name)
133 if name == ref {
134 v.OnBranch = true
135 }
136 case strings.HasPrefix(rf.Name, "refs/tags/"):
137 tags = append(tags, rf)
138 if strings.TrimPrefix(rf.Name, "refs/tags/") == ref {
143 139 v.OnTag = true
144 140 }
145 141 }
146 142 }
143 sort.Strings(v.Branches)
144 sort.SliceStable(tags, func(i, j int) bool {
145 if tags[i].When != tags[j].When {
146 return tags[i].When > tags[j].When
147 }
148 return tags[i].Name < tags[j].Name
149 })
150 v.Tags = make([]string, 0, len(tags))
151 for _, tag := range tags {
152 v.Tags = append(v.Tags, strings.TrimPrefix(tag.Name, "refs/tags/"))
153 }
147 154 return v
148 155 }
149 156