Versioning
How versions are chosen, enforced by git hooks, cut into releases, and read in the changelog.
Overterm uses SemVer. The version lives in one file,
VERSION, and every commit that changes the app bumps it in the same commit.
That is enforced by a git hook rather than remembered, which is why the
changelog has an entry for every version and no gaps.
What the parts mean
| Part | When |
|---|---|
| major | something incompatible: a saved-state format older versions cannot read, a removed feature or shortcut |
| minor | a new user-visible feature or capability |
| patch | a fix, performance work, polish, or an internal step of a larger feature |
The choice is about the change’s effect on someone using the app, not about how much code moved.
The hooks
make hooks points git at the repository’s own hooks, once per clone. There
are two.
pre-commit refuses a commit that changes the app without a new VERSION.
“The app” means anything under Sources/, Resources/ or Scripts/, or
Package.swift, Makefile or mise.toml. The message tells you what to
run:
Scripts/bump-version.sh minor "tabs: what changed"
git add VERSION CHANGELOG.md
SKIP_VERSION_CHECK=1 git commit … lets one through — needed when amending a
commit that bumped it already, because the check compares against HEAD,
which an amend replaces.
post-commit tags a commit that changed VERSION with an annotated
v<version>. If that tag already exists elsewhere it says so and leaves it
alone. Tags stay local until you push them.
bump-version.sh
Scripts/bump-version.sh major|minor|patch "area: what changed"
It sets VERSION one step past the committed version — so running it
twice before a commit does not bump twice — and adds the line to
CHANGELOG.md under a heading for the new version and today’s date. Run it
again before committing and it adds another bullet to the same entry.
Commit VERSION and CHANGELOG.md with the change itself, not separately.
Cutting a release
Push the commit and its tag, then run the workflow by hand:
git push origin main --tags
GitHub → Actions → Release → Run workflow. A macOS runner tests, builds
Overterm.app, packs a DMG, and publishes release v<version> with that
version’s CHANGELOG.md entry as the notes. It refuses a version that is
already released — bump first.
Nothing triggers it on push: a macOS runner is expensive, so releases are
deliberate. Locally the same pieces are make app dmg and
Scripts/release-notes.sh.
There is one scheduled workflow, and it is not about releases: once a week it checks whether Ghostty has tagged a release newer than the pinned one and opens an issue if so. Bumping the pin is by hand, because Xcode and Zig requirements move with it.
Reading the version you have
Overterm ▸ About Overterm shows, for example, “Version 2.14.0 (147)” —
the version from VERSION, and in brackets the build number, which is the
count of commits on the branch it was built from. Under it: the commit it was
built from (with -dirty if the tree was not clean) and the day it was
built.
⌥⌘O, View Latest Changelog, shows what the installed build added; the changelog is bundled into the app for exactly that. Settings ▸ About has the same thing, plus the update check.
The changelog
CHANGELOG.md on GitHub
is the history, newest first, one heading per version with its date and one
bullet per change. Release notes on the
releases page are that
version’s entry, generated from the same file — so there is one history, not
two.
Reading it is worth a note: the bullets are written as the change, in the
area it touched — overgit: the git panel in the sidebar,
diff: the file-diff card, out of the changes pane. A run of patch versions
with internal-sounding bullets is usually one feature being built; the minor
version at the end of the run is the one that landed it.
Version 1.0.0 is the original import of the project, and its entry covers the commits up to that point.