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.

Refresh the issue index from what changed

34a404b394dd9abcce0a67e32e99342c69595413 · Keenan Nemetz · 10d ago · parent fdf2340f

Refresh the issue index from what changed

A page read after a write used to reload every issue and renumber the repository from the whole branch history. Ensure now applies the difference between the indexed commit and the tip: it reloads only changed issues, adds only the numbers the range created, and leaves every other row alone. A rewritten branch or a missing index still falls back to the full rebuild.

The detail page and the browser write handlers now read one issue instead of the whole issue tree. Issue writes no longer re-validate the whole metadata tree after a write the writer already validated; the pre-receive hook still owns that check for pushes.

metadata/number.go +30−15

@@ -88,30 +88,45 @@ func LoadNumbers(g *git.Repo, ref string) (*Numbers, error) {
88 88 func RankAdditions(commits [][]string) *Numbers {
89 89 n := newNumbers()
90 90 next := 1
91 for _, e := range Additions(commits) {
92 if _, seen := n.byID[e.ID]; seen {
93 continue
94 }
95 n.byID[e.ID] = next
96 n.byNo[next] = e.ID
97 n.kind[e.ID] = e.Kind
98 next++
99 }
100 return n
101 }
102
103 // Entity is one thing the numbering sequence counts.
104 type Entity struct {
105 ID string
106 Kind string
107 }
108
109 // Additions turns per-commit path lists into the entities those commits created,
110 // oldest commit first and ULID-ordered within one commit. It is the half of
111 // RankAdditions that an incremental refresh reuses: a range of new commits can
112 // be ranked without replaying the whole history.
113 func Additions(commits [][]string) []Entity {
114 var out []Entity
91 115 for _, paths := range commits {
92 type entity struct{ id, kind string }
93 var batch []entity
116 var batch []Entity
94 117 for _, path := range paths {
95 118 if m := numberIssuePathRE.FindStringSubmatch(path); m != nil {
96 batch = append(batch, entity{id: m[1], kind: KindIssue})
119 batch = append(batch, Entity{ID: m[1], Kind: KindIssue})
97 120 continue
98 121 }
99 122 if m := numberRequestPathRE.FindStringSubmatch(path); m != nil {
100 batch = append(batch, entity{id: m[1], kind: KindRequest})
123 batch = append(batch, Entity{ID: m[1], Kind: KindRequest})
101 124 }
102 125 }
103 sort.Slice(batch, func(i, j int) bool { return batch[i].id < batch[j].id })
104 for _, e := range batch {
105 if _, seen := n.byID[e.id]; seen {
106 continue
107 }
108 n.byID[e.id] = next
109 n.byNo[next] = e.id
110 n.kind[e.id] = e.kind
111 next++
112 }
126 sort.Slice(batch, func(i, j int) bool { return batch[i].ID < batch[j].ID })
127 out = append(out, batch...)
113 128 }
114 return n
129 return out
115 130 }
116 131
117 132 // Of returns the number an entity was given.