git notes as a storage mechanism
Am working on a project build tool to make repeatable tasks for Micrantha projects easier.
A module of this tool is automatic versioning using semantic version.
The way I wanted the versioning to work is to have thresholds for when a version component auto-increments.
- A patch version will increment after 300 builds
- A minor version will increment after 100 patch builds
This is a potential feature that projects can use as a reminder to bump a version if there are breaking changes.
For every build, the build number is incremented, and thus potentially the rest of the version.
A question that arose, is where does one store a build number that:
- Changes often
- Differentiates between users?
Storing a build number
My initial attempt was to store the build number as a hidden file in the project.
Which is fine and worked, but the sheer amount of foreseeable conflicts is enough to make anyone rethink that approach.
And really, why should build information exist in a source repository. A build is the action with the object, not the object.
Storing release versions in git-tags is accepted practice.
It was conceivable that tags could also be used for a build number.
Experimenting a bit I tried tagging from a release tag with a build number under a prefix (like build/20).
But to retrieve the build number, one would have to rely on git-describe or a sorted tag list to pop from.
- I could not get git-describe to use the latest build tag
- why do I need a list of tags for every build?
In any case, it was not fruitful and I looked for alternatives.
Using git-notes as a secondary storage method could better separate the building from the source.
There are some obvious advantages:
- Git notes can be created on a file in the repository (the project configuration file)
- They are not pushed by default
- They have separate merge strategies when conflicts occur
This seems ideal. Might as well put notes with the current version on commits too with a hook.
To push the notes is a little ugly, put doable with an alias/subcommand or by configuration (part of the project init step).
As the build versions must be semi consistent and sequential, the note must be created on a reference that will not change.
A quick proto in my build tool now has different storage methods.
- The library or file system in users home path ~/.local
- The repository or git-notes
If the repository storage will try to use build notes on the first commit. One could use release tags as well but I am not sure if there is a benefit to having more than one build note.
If there are no commits, then versioning switches back to the library.
And syncing between or specifying storage methods is possible.
The Reality and TODO
I have not tested merge conflicts with git notes.
If they prove to be just as problematic as a file in the repository there is a backup plan:
- Have a note just for the build numbers in a line based record
- Change the merge strategy to cat_sort_uniq to take the diff and sort removing duplicates
- The build number is the last/first record
- Reset/clear when the patch version increments
Eventually will write some unit tests 🤦 or hit a conflict between my machines and see.