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.

Number issues and change requests for human references

e05f1c48d4ee55635cd7b77889f0545137198106 · Keenan Nemetz · 13d ago · parent 41d1fee9

Number issues and change requests for human references

A ULID is an unreadable handle, and the 8-character prefix the list showed
is mostly timestamp: this repository's 27 issues shared seven distinct
six-character prefixes and two pairs already collided at eight. The part
people actually type carried almost no information.

Issues and change requests now share one gap-free sequence (#1, #42, ...)
derived from the creation order in the metadata branch's history, the way
one forge counts both in a single run.

The number is not stored. It is the rank of the entity's creation commit,
so nothing is written when an entity is created, a repository needs no
backfill, the same history gives the same numbers on every clone, and
`vole admin index rebuild` reproduces them from git. A ULID stays the
identity: paths, front matter, `closes:` and audit entries are unchanged,
and data/index.db only caches the mapping so a page render does not walk
history.

Every id-taking command accepts a number, `#42` links in a body through a
kind-agnostic /r/<repo>/n/42 route, and --closes resolves an alias to the
ULID before writing.

Closes #45

core/git/git.go +44

@@ -710,6 +710,50 @@ func (r *Repo) LogPath(rev, path string, n int, follow bool) ([]Commit, error) {
710 710 return parseCommits(out), nil
711 711 }
712 712
713 // addMarker starts each commit's block in AddedPathsPerCommit's output. It is a
714 // control character no path in a metadata tree can contain, so a path can never
715 // be mistaken for the separator. git takes it as a %x escape because a pretty
716 // format rejects a literal control byte.
717 const (
718 addMarker = "\x01"
719 addMarkerSpec = "%x01"
720 )
721
722 // AddedPathsPerCommit lists, oldest first, the paths each commit added, limited
723 // to the given pathspecs. A commit that added nothing under them is absent from
724 // the result, so a caller counting blocks is counting only commits that changed
725 // the tree it asked about.
726 func (r *Repo) AddedPathsPerCommit(rev string, pathspecs ...string) ([][]string, error) {
727 args := []string{"log", "--reverse", "--diff-filter=A", "--name-only", "--no-renames",
728 "--format=" + addMarkerSpec, rev, "--"}
729 args = append(args, pathspecs...)
730 out, errs, err := r.run(nil, args...)
731 if err != nil {
732 return nil, fmt.Errorf("log %q added paths: %w: %s", rev, err, errs)
733 }
734 var groups [][]string
735 var cur []string
736 flush := func() {
737 if len(cur) > 0 {
738 groups = append(groups, cur)
739 cur = nil
740 }
741 }
742 for _, line := range strings.Split(string(out), "\n") {
743 line = strings.TrimRight(line, "\r")
744 switch line {
745 case addMarker:
746 flush()
747 case "":
748 // git separates the format line and the names with blank lines.
749 default:
750 cur = append(cur, line)
751 }
752 }
753 flush()
754 return groups, nil
755 }
756
713 757 // BlameLine is one line of `git blame` output with the commit that last touched
714 758 // it. Line is the line number in the blamed revision.
715 759 type BlameLine struct {