Eric Bower
·
2026-02-25
1{{template "base" .}}
2
3{{define "title"}}patchbin{{end}}
4
5{{define "meta"}}
6<link rel="alternate" type="application/atom+xml"
7 title="RSS feed for git collaboration server"
8 href="/rss" />
9{{end}}
10
11{{define "body"}}
12<main class="group">
13 <div class="flex justify-center items-center">
14 <div class="box container w-full group">
15 <h1 class="text-xl">A pastebin for patches, supercharged for git collaboration</h1>
16
17 {{if .MetaData.Desc}}
18 <div class="box-sm">
19 <div>{{.MetaData.Desc}}</div>
20 </div>
21 {{end}}
22
23 <div>
24 Contributions are designed to be anonymous: the quality of your work
25 is what matters. No signup required, just connect with an SSH key.
26 </div>
27
28 <div>
29 The target project doesn't need to run patchbin for someone to
30 submit a patch request against it. It works like a pull request,
31 except both sides collaborate by sending rounds of patchsets: a
32 contributor sends patches, a reviewer replies with their own patches
33 on top, back and forth, as commits rather than comments. The result
34 is a collaborative workspace built entirely out of patches.
35 Reviewing means pulling the code down, not clicking through a diff
36 viewer. Issues work the same way: an issue is just a patch request
37 without any code attached yet, and anyone can follow up with a real
38 patch request on top of it.
39 </div>
40
41 <div>
42 There's no accept or reject step. A patch request is simply active
43 or inactive: active ones go inactive after 30 days without activity.
44 When a reviewer is happy with the code, they pull it, merge it, and
45 push upstream themselves; there's nothing to manage here beyond that.
46 </div>
47
48 <div class="group">
49 <h2>Quickstart</h2>
50
51 <div>
52 Submit a patch request (starts as a draft, visible only to you):
53 </div>
54 <pre class="m-0">git format-patch main --stdout | ssh {{.MetaData.URL}} pr create {repo}</pre>
55
56 <div>Open it so others can see it (also enables RSS notifications):</div>
57 <pre class="m-0">ssh {{.MetaData.URL}} pr open {prID}</pre>
58
59 <div>Checkout the latest patchset from a patch request:</div>
60 <pre class="m-0">ssh {{.MetaData.URL}} print pr-{prID} | git am -3</pre>
61
62 <div>Add a follow-up patchset (e.g. after addressing review comments):</div>
63 <pre class="m-0">git format-patch main --stdout | ssh {{.MetaData.URL}} pr add {prID}</pre>
64
65 <div>Help guide:</div>
66 <pre class="m-0">ssh {{.MetaData.URL}} help</pre>
67 </div>
68
69 <div class="group">
70 <h2>Commands</h2>
71
72 <details class="details-min">
73 <summary class="font-bold">pr - manage patch requests</summary>
74 <div class="group my">
75 <div>
76 <code>pr create {repo}</code> - submit a new PR from stdin (starts as draft)
77 <pre class="m-0">git format-patch main --stdout | ssh {{.MetaData.URL}} pr create {repo}</pre>
78 </div>
79 <div>
80 <code>pr add {prID}</code> - add a new patchset to an existing PR from stdin
81 <pre class="m-0">git format-patch main --stdout | ssh {{.MetaData.URL}} pr add {prID}</pre>
82 </div>
83 <div>
84 <code>pr open {prID} [--comment]</code> - transition draft → open, enables RSS notifications
85 <pre class="m-0">ssh {{.MetaData.URL}} pr open {prID}</pre>
86 </div>
87 <div>
88 <code>pr draft {prID} [--comment]</code> - transition open → draft, disables RSS notifications
89 <pre class="m-0">ssh {{.MetaData.URL}} pr draft {prID}</pre>
90 </div>
91 <div>
92 <code>pr edit {prID} {title}</code> - rename a PR
93 <pre class="m-0">ssh {{.MetaData.URL}} pr edit {prID} "new title"</pre>
94 </div>
95 <div>
96 <code>pr summary {prID}</code> - show metadata, patchsets, and patches for a PR
97 <pre class="m-0">ssh {{.MetaData.URL}} pr summary {prID}</pre>
98 </div>
99 <div>
100 <code>pr ls [repo] [--draft|--open|--active|--inactive|--mine]</code> - list PRs
101 <pre class="m-0">ssh {{.MetaData.URL}} pr ls {repo} --open</pre>
102 </div>
103 </div>
104 </details>
105
106 <details class="details-min">
107 <summary class="font-bold">issue - text-only patch requests</summary>
108 <div class="group my">
109 <div>
110 <code>issue create {repo} [--title]</code> - submit a new issue from stdin (starts as open)
111 <pre class="m-0">echo "steps to reproduce..." | ssh {{.MetaData.URL}} issue create {repo} --title "bug: crash on startup"</pre>
112 </div>
113 </div>
114 </details>
115
116 <details class="details-min">
117 <summary class="font-bold">ps - manage patchsets</summary>
118 <div class="group my">
119 <div>
120 <code>ps rm {patchsetID}</code> - remove a patchset and its patches (creator only)
121 <pre class="m-0">ssh {{.MetaData.URL}} ps rm ps-{patchsetID}</pre>
122 </div>
123 </div>
124 </details>
125
126 <details class="details-min">
127 <summary class="font-bold">print - print patches for checkout</summary>
128 <div class="group my">
129 <div>
130 <code>print pr-{prID}</code> - print the latest patchset for a PR
131 <pre class="m-0">ssh {{.MetaData.URL}} print pr-{prID} | git am -3</pre>
132 </div>
133 <div>
134 <code>print ps-{patchsetID}</code> - print a specific patchset
135 <pre class="m-0">ssh {{.MetaData.URL}} print ps-{patchsetID} | git am -3</pre>
136 </div>
137 </div>
138 </details>
139
140 <details class="details-min">
141 <summary class="font-bold">logs - event history</summary>
142 <div class="group my">
143 <div>
144 <code>logs [--pr ID] [--pubkey]</code> - list event logs, optionally filtered to a PR or your own activity
145 <pre class="m-0">ssh {{.MetaData.URL}} logs --pr {prID}</pre>
146 </div>
147 </div>
148 </details>
149 </div>
150
151 <div class="text-sm">
152 <a href="https://github.com/picosh/patchbin">Self-host your own patchbin</a>
153 </div>
154 </div>
155 </div>
156</main>
157{{end}}