Git Notes Storage

In 2020, I was experimenting with a project build tool for repeatable Micrantha workflows. One module attempted automatic versioning and needed somewhere to store frequently changing build metadata without turning that metadata into ordinary source changes.

The Versioning Experiment

The prototype used thresholds that could trigger version increments after a number of builds. Those numbers were arbitrary policy choices, not semantic versioning rules. The interesting question was where to keep mutable build state that:

  1. changes frequently
  2. may differ between users or machines
  3. should not create source-file conflicts

Why Not a Normal File?

My first attempt stored the build number in a hidden project file. That worked, but it coupled operational state to the source tree and created predictable merge-conflict pressure.

Release versions belong naturally in Git tags. Per-build counters are less obvious: creating a tag for every build produces another rapidly growing namespace and still requires a convention for selecting the authoritative value.

Git Notes

Git notes provide a separate ref namespace for attaching metadata to Git objects, commonly commits, without changing the objects themselves.

That made them interesting for the experiment because:

  1. notes do not alter the commit they annotate
  2. notes refs are separate from ordinary branch history
  3. notes are not transferred by the usual branch push/fetch configuration unless explicitly configured
  4. Git provides merge strategies for reconciling notes refs

The separation is useful, but it is not free storage. Anyone relying on notes still has to define how their refs are distributed, merged, backed up, and selected as authoritative state.

Prototype Storage Choices

The prototype eventually had two storage modes:

  1. a per-user value under ~/.local
  2. repository-associated metadata stored in Git notes

The local mode avoided distributed coordination entirely. The notes mode made metadata portable with the repository, but only when the notes ref was explicitly synchronized.

That tradeoff turned out to be the real lesson: where state lives determines who has to coordinate it.

What Remained Unresolved

I never completed enough multi-writer testing to claim that Git notes solved the problem. Concurrent updates can still require reconciliation, and a sequential build number is itself a coordination problem if multiple machines are allowed to advance it.

A line-oriented notes record with an appropriate merge strategy was one idea, but it would still need a rule for ordering and conflict resolution. At that point, the system starts looking less like “free metadata” and more like a small distributed state store.

For local tooling or annotations, Git notes remain useful. For authoritative shared counters, releases, or deployment state, I would now start by asking whether that state belongs in Git at all.