Skip to main content

max / makenotwork

docs: document git notes, and say so on the git landing page The feature is undiscoverable without this. Nothing on a repository page explains what a note is to somebody who has never seen one, and the two commands that make notes usable from a terminal are not guessable. The page's spine is those two commands. Fetching is the refspec line already printed on the Notes tab. Pushing is a push to the inbox ref, documented as the ordinary way to push notes rather than as a recovery step, because it is: merge_and_publish treats a missing local ref and no shared history as the same case, and cat_sort_uniq is idempotent, so the inbox is correct for a first push as much as a contended one. Telling people to try the plain push first would only teach them to recognise a rejection they never need to see. This closes what the plan called P3's client half. There is no mnw client binary and none is warranted: mnw-cli is the server-side SSH host, so a push fallback cannot live there, and the two planned verbs reduce to git clone plus one config line and a push to a longer ref name.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-08 22:37 UTC
Signed with PGP, not checked
Commit: b084fb9b844c7052d3fdccbd2fddd3f4752d16c0
Parent: c6cba8c
4 files changed, +97 insertions, -0 deletions
@@ -7196,6 +7196,7 @@
7196 7196 .git-note-namespaces a:hover { opacity: 1; }
7197 7197 .git-note-namespaces a.is-selected { opacity: 1; text-decoration: underline; }
7198 7198 .git-note-target-kind { opacity: 0.6; }
7199 + .git-explore-intro { margin: 0 0 var(--gap-section); font-size: var(--text-note); opacity: 0.8; }
7199 7200 .git-notes-fetch { padding-bottom: var(--gap-section); font-size: var(--text-note); }
7200 7201 .git-notes-fetch p { margin: 0 0 var(--gap-peer); }
7201 7202 .git-note-feed-cap { font-size: var(--text-fine); opacity: 0.6; padding-top: var(--gap-section); }
@@ -31,6 +31,7 @@
31 31 - **Per-file history**: Commit log filtered to a single file's changes
32 32 - **Raw file access**: View or download raw file contents at `/git/username/repo-name/raw/branch/path/to/file`
33 33 - **Ref selector**: Switch between branches and tags from any view
34 + - **Notes**: Annotations attached to commits and files, rendered wherever the object appears. See [Git Notes](./git-notes.md).
34 35
35 36 The overview shows the tree at HEAD and renders README.md as HTML if present.
36 37
@@ -112,5 +113,6 @@
112 113
113 114 ## See Also
114 115
116 + - [Git Notes](./git-notes.md): Annotating commits, and how to fetch and push notes
115 117 - [Content & Items](./02-content.md): Publishing releases
116 118 - [Projects](./projects.md): Project setup
@@ -9,6 +9,15 @@
9 9
10 10 <h1 class="git-repo-name">Repositories</h1>
11 11
12 + {# Notes are the one thing this browser does that no other forge does, and
13 + nothing on a repository page says so to somebody who has never seen a
14 + note. The landing page is where that sentence reaches everybody. #}
15 + <p class="git-explore-intro">
16 + Every repository here renders <a href="/docs/git-notes">git notes</a>:
17 + annotation attached to a commit without rewriting it, stored in the
18 + repository and carried by a clone.
19 + </p>
20 +
12 21 {% if repos.is_empty() %}
13 22 {% call ui::empty_state("", "No public repositories yet.") %}{% endcall %}
14 23 {% else %}
@@ -1,0 +1,85 @@
1 + # Git Notes
2 +
3 + Git has always been able to attach a note to a commit without rewriting it. Almost nobody uses the feature, because no forge renders notes and no clone fetches them. MNW renders them, lets you write them from the browser, and accepts pushes that plain git would reject.
4 +
5 + Notes are ordinary git objects living on `refs/notes/*`. Everything MNW knows about a note is in your repository, not in a database only we can read. Clone the repo and the notes come with it.
6 +
7 + ## Reading Notes
8 +
9 + Nothing to set up. If a repository has notes, they appear:
10 +
11 + - On the commit page, one panel per namespace, rendered as markdown.
12 + - As a badge on commit log rows, so you can see which commits are annotated.
13 + - On the Notes tab at `/git/username/repo-name/notes`, which lists every namespace with its count and a reverse-chronological feed of annotations.
14 + - On the file and blame views, alongside the commit being shown.
15 +
16 + ## Fetching Notes Into Your Clone
17 +
18 + A clone does not fetch notes, and git offers no way to change that default. Set the refspec once per clone:
19 +
20 + ```
21 + git config --add remote.origin.fetch '+refs/notes/*:refs/notes/*'
22 + ```
23 +
24 + Every `git fetch` after that brings notes along. Read them with `git notes show <commit>`, or point git at a namespace other than the default with `git notes --ref=<namespace> show <commit>`.
25 +
26 + This one line is most of why notes go unused everywhere. It is printed on the Notes tab of every repository so you never have to remember it.
27 +
28 + ## Writing Notes From the Browser
29 +
30 + Open any commit page in a repository you can push to. Each namespace panel has add, edit and delete controls, and you can create a new namespace by naming one.
31 +
32 + Notes written this way are committed as `Your Display Name <username@users.makenot.work>`. Your account email address never enters the repository's object graph, because an address in a public repo is permanent and clonable by anyone who fetches the notes ref.
33 +
34 + Write access follows push access: the repository owner and any collaborator with push permission.
35 +
36 + ## Pushing Notes From Your Machine
37 +
38 + Push notes to the inbox ref for the namespace:
39 +
40 + ```
41 + git push origin refs/notes/commits:refs/mnw/notes-inbox/commits
42 + ```
43 +
44 + Replace `commits` with your namespace on both sides. The server merges what you pushed into `refs/notes/commits` and reports the merged tip:
45 +
46 + ```
47 + notes: merged into refs/notes/commits
48 + ```
49 +
50 + Then fetch to see the result:
51 +
52 + ```
53 + git fetch origin
54 + ```
55 +
56 + Use this in place of `git push origin refs/notes/commits`. The plain push works when nobody else has written a note since you last fetched, and fails with a non-fast-forward rejection when somebody has. The inbox never fails, because the ref you are pushing to does not exist on the server: MNW deletes it as soon as it has merged your notes, so every push creates it fresh. There is no rejection to recover from and no case where the inbox is the wrong target, including the first push to a repository with no notes at all.
57 +
58 + The merge uses git's `cat_sort_uniq` strategy. When two people annotate the same commit, both notes survive, sorted and deduplicated. Nothing is discarded and nothing is doubled if the same push is processed twice.
59 +
60 + If the server does not answer, the push prints:
61 +
62 + ```
63 + notes: received, merge deferred (the server did not answer)
64 + ```
65 +
66 + Your notes are safe in the inbox ref and the next push to that namespace merges them.
67 +
68 + ## Namespaces
69 +
70 + The default namespace is `commits`, which is what bare `git notes` uses. Any other name gives you a separate track of annotation on the same commits: `review`, `design`, `deploys`.
71 +
72 + Namespace names may contain letters, numbers, hyphens, underscores, dots and slashes, up to 64 characters, and follow git's ref naming rules. A component cannot start with a dot, contain `..`, or end in `.lock`. Note content is capped at 50,000 characters.
73 +
74 + `refs/notes/mnw/*` is reserved. It is where MNW writes its own metadata about your commits, and the web editor, the API and pushes all refuse it. Everything outside that prefix is yours.
75 +
76 + ## Annotating Files
77 +
78 + Git notes can annotate any object, not only commits. A note on a blob is a note on one exact version of one file, and MNW shows it on that file's page. Most tools assume commits and quietly find nothing on the rest.
79 +
80 + Notes on blobs are read-only in the browser for now. Write them with `git notes --ref=<namespace> add <blob-oid>` and push them the same way as any other note.
81 +
82 + ## See Also
83 +
84 + - [Git Source Browser](./git.md): browsing, cloning, issues and patches
85 + - [Export](./export.md): taking your data with you