vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
Phase 7 slice 1: review on the web, so approving does not start with a clone
78912785b00227cffe3f8fb26b057cd60159a6b4 · Keenan Nemetz · 18d ago · parent 9bea7f11
Phase 7 slice 1: review on the web, so approving does not start with a clone Phase 7 is re-scoped: signing is deferred (the SSH handshake already establishes who pushed, and there is no third-party verifier here), and the phase is now about the experience of using the forge. - GET /r/<repo>/commit/<sha>: a commit's metadata and the patch it introduced, per-file hunks with line numbers; the commit list links to it - change requests show the same diff, computed three-dot: a review is what the branch adds since it diverged, not every commit main gained meanwhile - diffs are capped at 512 KiB and labelled when cut, binary files are named rather than faked, and every line is escaped (a <script> line is a test) - the repository README renders on its home page and markdown blobs render as markdown, through the sanitiser issues already use
internal/gitx/gitx.go +38
| @@ -660,6 +660,44 @@ func (r *Repo) TreeBlobs(treeish string) (map[string]Blob, error) { | |||
| 660 | 660 | return blobs, nil | |
| 661 | 661 | } | |
| 662 | 662 | ||
| 663 | // Diff returns the unified diff git prints between two revisions, capped at | ||
| 664 | // maxBytes. A range may be written with git's own syntax ("main...feature"), so | ||
| 665 | // the caller decides between two-dot and merge-base semantics. | ||
| 666 | func (r *Repo) Diff(rangeOrFrom, to string, maxBytes int) (string, bool, error) { | ||
| 667 | args := []string{"diff", "--no-color", "--no-ext-diff", "--find-renames", "--unified=3"} | ||
| 668 | if to == "" { | ||
| 669 | args = append(args, rangeOrFrom) | ||
| 670 | } else { | ||
| 671 | args = append(args, rangeOrFrom, to) | ||
| 672 | } | ||
| 673 | out, errs, err := r.runHead(maxBytes, args...) | ||
| 674 | if err != nil { | ||
| 675 | return "", false, fmt.Errorf("diff: %w: %s", err, errs) | ||
| 676 | } | ||
| 677 | return string(out), len(out) == maxBytes, nil | ||
| 678 | } | ||
| 679 | |||
| 680 | // ShowPatch is the patch of one commit against its parent (or the empty tree for | ||
| 681 | // a root commit). `git show` gets that case right, which is why it is used here | ||
| 682 | // instead of assembling a range by hand. | ||
| 683 | func (r *Repo) ShowPatch(rev string, maxBytes int) (string, bool, error) { | ||
| 684 | out, errs, err := r.runHead(maxBytes, | ||
| 685 | "show", "--format=", "--patch", "--no-color", "--no-ext-diff", "--find-renames", "--unified=3", rev) | ||
| 686 | if err != nil { | ||
| 687 | return "", false, fmt.Errorf("show %s: %w: %s", rev, err, errs) | ||
| 688 | } | ||
| 689 | return string(out), len(out) == maxBytes, nil | ||
| 690 | } | ||
| 691 | |||
| 692 | // CommitBody is a commit's full message, for the commit page. | ||
| 693 | func (r *Repo) CommitBody(rev string) (string, error) { | ||
| 694 | out, errs, err := r.run(nil, "show", "-s", "--format=%B", rev) | ||
| 695 | if err != nil { | ||
| 696 | return "", fmt.Errorf("show -s %s: %w: %s", rev, err, errs) | ||
| 697 | } | ||
| 698 | return strings.TrimSpace(string(out)), nil | ||
| 699 | } | ||
| 700 | |||
| 663 | 701 | // AllBlobs lists every blob reachable from any ref, with its size. It is the | |
| 664 | 702 | // mark phase of garbage collection, so it walks history rather than tips: an | |
| 665 | 703 | // old commit still serves its files. | |