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.
Show which branch a change request came from
8e1005eb2c104934adef950c5afc090d4025ce06 · Keenan Nemetz · 13d ago · parent b7ac1a00
Show which branch a change request came from A request records the exact commit under review, and the page showed only that: `main ← 43f98bcd`. The branch the work is on is how people talk about a change, fetch it, and find it after it lands, and it was being thrown away when the request was opened — the web form resolved the chosen branch to a commit and kept only the commit. `request.md` now records `head_ref:` beside `head:`. It is a display hint and nothing else: approvals, checks, the diff and the landing gate still name the commit, and a test pins that a branch name cannot authorise a different tip. The request page, the request list and `vole change show` show it, and the page marks the branch as moved or deleted when it no longer points at the reviewed commit, so the name reads as provenance rather than as a claim about what is being reviewed. It is optional on read: records written before it existed still load, and a request opened from a bare commit id records no branch.
server/web/request_view.go +14−1
| @@ -55,6 +55,10 @@ type requestSidebarView struct { | |||
| 55 | 55 | Current int | |
| 56 | 56 | CanApprove bool | |
| 57 | 57 | CanClose bool | |
| 58 | // HeadRefNote says when the branch the request names no longer points at the | ||
| 59 | // commit under review ("branch moved", "branch deleted"), so the name is read as | ||
| 60 | // provenance rather than as a claim about what is being reviewed. | ||
| 61 | HeadRefNote string | ||
| 58 | 62 | // CanMerge is the merge control: true only when the gate would accept the | |
| 59 | 63 | // landing now, so the button never offers something the handler would refuse. | |
| 60 | 64 | CanMerge bool | |
| @@ -116,6 +120,15 @@ func (w *Web) requestSidebar(r *http.Request, m *repo.Meta, req *metadata.Reques | |||
| 116 | 120 | who := w.accountName(r) | |
| 117 | 121 | approvable := req.Open() && canApproveRequest(acl, who, req.Author) | |
| 118 | 122 | canClose := canTriage(acl, who, req.Author) | |
| 123 | headRefNote := "" | ||
| 124 | if req.HeadRef != "" { | ||
| 125 | switch tip, err := m.Git().RevParse("refs/heads/" + req.HeadRef); { | ||
| 126 | case err != nil || tip == "": | ||
| 127 | headRefNote = "branch deleted" | ||
| 128 | case tip != req.Head: | ||
| 129 | headRefNote = "branch moved" | ||
| 130 | } | ||
| 131 | } | ||
| 119 | 132 | // Preflight the landing rather than guessing from the approval count: the same | |
| 120 | 133 | // gate the handler calls is asked here, so the button and the write agree about | |
| 121 | 134 | // approvals, checks and conflicts. | |
| @@ -147,7 +160,7 @@ func (w *Web) requestSidebar(r *http.Request, m *repo.Meta, req *metadata.Reques | |||
| 147 | 160 | return requestSidebarView{ | |
| 148 | 161 | Page: w.page(r, title), Name: m.Name, Request: req, | |
| 149 | 162 | Approvals: approvals, Checks: checks, Required: required, Current: current, | |
| 150 | CanApprove: approvable, CanClose: canClose, | ||
| 163 | CanApprove: approvable, CanClose: canClose, HeadRefNote: headRefNote, | ||
| 151 | 164 | CanMerge: mergeable, MergeBlocked: mergeBlocked, | |
| 152 | 165 | CanDiscuss: w.canDiscuss(r, acl), | |
| 153 | 166 | ContributorCI: contributorCI, | |