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.

Sort the issue list by when it last moved

db4081ec934ddd9a7ce123b4d3cf6d6ea43a4537 · Keenan Nemetz · 4d ago · parent a32a859a

Sort the issue list by when it last moved

An issue queue is read for what changed, not for the order things were
filed. The list now shows the newest activity first and carries the columns
that answer the question: labels have their own column, assignees render like
authors do, and the creation time and author sit under the title.

The last column is "updated": the newest commit over the issue's directory,
which covers an edit, a comment, a label change, and a close or reopen. The
metadata branch has no such field on purpose — the commit carries the time —
so the index derives it from one `git log` per rebuild or one per refreshed
range, and stores it. An incremental refresh also reads the commits' paths, so
an edit reverted inside the range still counts as activity.

Bumps the index schema version, which drops the derived rows and rebuilds them
from the branch on the next read.

Closes #192

core/git/git.go +42−6

@@ -451,20 +451,56 @@ func (r *Repo) CommitTree(tree, parent, msg string) (string, error) {
451 451 // One `git log` answers for a whole subtree, so a record's attestation costs one
452 452 // process for all of them rather than one per file.
453 453 func (r *Repo) LastTouchedByPath(rev, dir string) (map[string]string, error) {
454 out, errs, err := r.run(nil, "log", "--format=%x00%H", "--name-only", rev, "--", dir)
454 return r.touchedByPath(rev, dir, "%H")
455 }
456
457 // TouchTimes is LastTouchedByPath for the question a list asks: when was each
458 // path under dir last changed? Rev may be a commit range, so an incremental
459 // reader only walks the commits it has not seen.
460 //
461 // The metadata format deliberately has no `updated` field — the commit that
462 // changed a file already carries the time, and writing it back would add a
463 // changed line to every edit. This is how the index turns one `git log` into a
464 // per-file time, rather than one process per entity.
465 func (r *Repo) TouchTimes(rev, dir string) (map[string]int64, error) {
466 touched, err := r.touchedByPath(rev, dir, "%at")
467 if err != nil {
468 return nil, err
469 }
470 if len(touched) == 0 {
471 return nil, nil
472 }
473 times := make(map[string]int64, len(touched))
474 for path, when := range touched {
475 t, err := strconv.ParseInt(when, 10, 64)
476 if err != nil {
477 continue
478 }
479 times[path] = t
480 }
481 return times, nil
482 }
483
484 // touchedByPath attributes every path under dir reachable from rev to the newest
485 // commit that touched it, reading the commit field named by format.
486 func (r *Repo) touchedByPath(rev, dir, format string) (map[string]string, error) {
487 if rev == "" || rev == ZeroSHA {
488 return nil, nil
489 }
490 out, errs, err := r.run(nil, "log", "--format=%x00"+format, "--name-only", rev, "--", dir)
455 491 if err != nil {
456 492 return nil, fmt.Errorf("log %s: %w: %s", dir, err, errs)
457 493 }
458 494 touched := map[string]string{}
459 // Each record starts with a NUL and the commit id, so paths that share a commit
460 // are attributed without guessing where one commit's list ends.
495 // Each record starts with a NUL and the commit field, so paths that share a
496 // commit are attributed without guessing where one commit's list ends.
461 497 for _, chunk := range bytes.Split(out, []byte{0})[1:] {
462 498 lines := strings.Split(strings.TrimSpace(string(chunk)), "\n")
463 499 if len(lines) == 0 {
464 500 continue
465 501 }
466 sha := strings.TrimSpace(lines[0])
467 if sha == "" {
502 value := strings.TrimSpace(lines[0])
503 if value == "" {
468 504 continue
469 505 }
470 506 for _, line := range lines[1:] {
@@ -473,7 +509,7 @@ func (r *Repo) LastTouchedByPath(rev, dir string) (map[string]string, error) {
473 509 continue
474 510 }
475 511 if _, seen := touched[path]; !seen {
476 touched[path] = sha
512 touched[path] = value
477 513 }
478 514 }
479 515 }