Git Notes
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.
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.
Reading Notes
Nothing to set up. If a repository has notes, they appear:
- On the commit page, one panel per namespace, rendered as markdown.
- As a badge on commit log rows, so you can see which commits are annotated.
- On the Notes tab at
/git/username/repo-name/notes, which lists every namespace with its count and a feed of annotations, newest first. - On the file and blame views, alongside the commit being shown. An annotated line in blame links straight to its note.
Searching Notes
The Notes tab has a search box. It searches note text within the selected namespace, and understands quoted phrases and a leading - to exclude a word. There is a filter for notes on commits, which hides notes written on files and other objects.
Search reads an index MNW builds from your repository. The repository is the source of truth: the index can be dropped and rebuilt from the refs at any time, and nothing about a note is stored only there.
Following Notes As a Feed
Every repository has an RSS feed of its annotations at:
/git/username/repo-name/notes.rss
Add ?namespace=review for one namespace. Items are ordered by when each annotation was written, so annotating an old commit is news. Private repositories have no feed.
Fetching Notes Into Your Clone
A clone does not fetch notes, and git offers no way to change that default. Set the refspec once per clone:
git config --add remote.origin.fetch '+refs/notes/*:refs/notes/*'
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>.
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.
Writing Notes From the Browser
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.
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.
Write access follows push access: the repository owner and any collaborator with push permission.
Pushing Notes From Your Machine
Push notes to the inbox ref for the namespace:
git push origin refs/notes/commits:refs/mnw/notes-inbox/commits
Replace commits with your namespace on both sides. The server merges what you pushed into refs/notes/commits and reports the merged tip:
notes: merged into refs/notes/commits
Then fetch to see the result:
git fetch origin
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.
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.
If the server does not answer, the push prints:
notes: received, merge deferred (the server did not answer)
Your notes are safe in the inbox ref and the next push to that namespace merges them.
Reading and Writing Notes From a Script
There is a JSON API under /api/git/username/repo-name/notes, for tooling that wants to annotate a commit without running git. A build script recording its result, a review bot recording a verdict.
Reads need no credential on a public repository:
curl https://makenot.work/api/git/username/repo-name/notes
curl 'https://makenot.work/api/git/username/repo-name/notes/<commit>?namespace=review'
curl 'https://makenot.work/api/git/username/repo-name/notes/search?q=timeout'
Writes need a personal access token with push permission, the same token git push over HTTPS uses. Create one under Access Tokens on your SSH keys settings page, and send it as the HTTP Basic password. The username half is ignored:
curl -u x:$MNW_TOKEN -X PUT \
-H 'Content-Type: application/json' \
-d '{"namespace":"builds","content":"passed on 2 targets"}' \
https://makenot.work/api/git/username/repo-name/notes/<commit>
curl -u x:$MNW_TOKEN -X DELETE \
'https://makenot.work/api/git/username/repo-name/notes/<commit>?namespace=builds'
A write is a real git commit on refs/notes/<namespace>, so a note written this way is fetched, read and pushed like any other. Two writers annotating the same commit are merged rather than one overwriting the other, and the response says "merged": true when that happened, meaning the stored note is not exactly what you sent.
A session cookie is not accepted for writes. A token is, which is what a script has.
Namespace and content rules are the browser’s: refs/notes/mnw/* is refused, and content is capped at 50,000 characters.
Search is the one endpoint answered from the index rather than from your repository, since a full-text query cannot be served by walking a tree. Its response carries "indexed": false when MNW has not yet indexed the repository, so an empty result is never mistaken for no matches.
The full request and response shapes are in the OpenAPI spec, under the Git Notes tag.
Namespaces
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.
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.
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.
What MNW Writes
Three namespaces under the reserved prefix carry metadata MNW computes about your repository. They are ordinary notes: they clone, they fetch, they read with git notes --ref=mnw/builds show <commit>, and they are yours to keep if you leave.
| Namespace | On | Says |
|---|---|---|
mnw/builds | the commit a built tag points at | build status, version, tag, targets, and the error if it failed |
mnw/issues | each commit whose message referenced an issue | which issues it closed, reopened or referenced |
mnw/scan | the commit a release was built from | how that release’s artifacts scanned |
Each note is a short list of key: value lines, readable at a terminal and parseable by a script.
These are read-only in the browser and refused on push, which is what “reserved” means in practice. MNW rewrites a note whole when the fact changes, so rebuilding a tag replaces its build note rather than adding a second one.
mnw/scan is written once every artifact in a release has a verdict, so it never reports a partial result. Its verdict is the worst verdict of any artifact in the release.
Annotating Files
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.
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.
See Also
- Git Source Browser: browsing, cloning, issues and patches
- Export: taking your data with you