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.
Let an author move their change request's head from the browser
53ff967be619894b62ca0ca69cd9a9f5f52bce01 · Keenan Nemetz · 13d ago · parent 8e1005eb
Let an author move their change request's head from the browser A request names the exact commit under review, so a fixup pushed after it was opened is invisible until the head moves. The only mover was `vole change update --head`, which writes the metadata branch — a write a contributor cannot make. The person who owns the branch was the one person who could not keep the request current. The request page now offers the author (or a maintainer) a branch picker that moves an open request's head to that branch's tip. It applies the same rule the new-request form does: the head must be a branch tip, and a contributor may only name a branch under their own namespace, which is what the pre-receive hook would have let them push. Approvals stay in the tree as history and stop matching, which is what a new head already means. SetRequestHead now refuses a closed or merged request, so the CLI and the browser share that rule instead of the web handler owning it alone.
server/web/templates/requests.html +13
| @@ -108,6 +108,19 @@ | |||
| 108 | 108 | <dt>Base</dt><dd><code>{{.Request.Base}}</code></dd> | |
| 109 | 109 | <dt>Head</dt><dd>{{with .Request.HeadRef}}<code title="the branch the request was opened from">{{.}}</code>{{if $.HeadRefNote}} <span class="muted">({{$.HeadRefNote}})</span>{{end}} {{end}}<a class="sha" href="/r/{{.Name}}/commit/{{.Request.Head}}">{{short .Request.Head}}</a></dd> | |
| 110 | 110 | </dl> | |
| 111 | {{if .CanMoveHead}} | ||
| 112 | <form method="post" action="/r/{{.Name}}/requests/{{.Request.ID}}/head" class="head-move"> | ||
| 113 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | ||
| 114 | <label>Move head to | ||
| 115 | <select name="head" required> | ||
| 116 | <option value="" selected disabled>Choose a branch</option> | ||
| 117 | {{range .HeadBranches}}<option value="{{.}}">{{.}}</option>{{end}} | ||
| 118 | </select> | ||
| 119 | </label> | ||
| 120 | <button class="secondary" type="submit"{{if not .HeadBranches}} disabled{{end}}>{{icon "rotate-ccw"}}Update</button> | ||
| 121 | </form> | ||
| 122 | {{if not .HeadBranches}}<p class="muted">Push a branch first.</p>{{end}} | ||
| 123 | {{end}} | ||
| 111 | 124 | </section> | |
| 112 | 125 | ||
| 113 | 126 | <section> | |