governance / Documentation versioning
DocsGovernanceDocumentation versioning

Documentation versioning

How the docs of each product (gitaiflow, astwire, …) are versioned, and how to release a new version. For the version of the docs site itself, see RELEASING.md.

5 min readGovernance
On this page ▾
  1. 1. The model
  2. 2. Declare the versions (projects/<slug>/project.json)
  3. 3. Mark every doc with the version it appeared in
  4. 4. Release a new version of a product
  5. Which ref for which version
  6. 5. Frozen versions in the build
  7. CI requirements
  8. Warnings

Audience: anyone who edits a product's docs or cuts a release.


1. The model

One docs tree, always the latest. Older versions are either filtered views of that tree (from each doc's header) or built from a git ref (a tag or a branch). Nothing is copied per version.

Kind Built from Use it when
Filtered view (default) The latest docs, narrowed by each doc's since / removed A release only adds or removes pages. Same text in every version.
Frozen snapshot A git tag of this repo (<slug>/v<version>) An end-of-life version whose text must stay exactly as it was.
Maintenance branch A git branch (e.g. release/1.4) A supported older version that still gets doc fixes.

Start with filtered views. Move a version to a tag or branch only when its wording has to differ from the latest.


2. Declare the versions (projects/<slug>/project.json)

json
"versions": [
  { "id": "1.1.3", "status": "current" },
  { "id": "1.1.1", "status": "supported" },
  { "id": "1.0.0", "status": "eol", "ref": "gitaiflow/v1.0.0" }
]
Field Meaning
id A release: an exact version (1.1.3) or a release line (1.1). Use one style per project. Lifecycle fields are compared at the precision of the id: with line ids, since: 1.1.3 counts as part of 1.1.
status current (what the normal URLs show; the first entry if none says so), supported, or eol.
label Optional display name. Default: the id, plus "(latest)" on the current one.
ref Optional git tag or branch to build this version from. Default: the tag <slug>/v<id> if it exists. tag is the older spelling of the same thing.

List versions newest first. One entry shows the version as a plain label with no dropdown; no versions list means no version UI at all.


3. Mark every doc with the version it appeared in

yaml
---
since: 1.1.3        # added in this version (required in a versioned project)
changed: 1.1.4      # last meaningful change (optional)
deprecated: 1.2.0   # optional
removed: 1.3.0      # optional
---
  • A doc belongs to version V when since <= V and V < removed.
  • Choosing an older version in the dropdown hides docs that didn't exist yet (sidebar, search, previous/next). A page outside the chosen version says so.
  • "Added in X" is shown only on docs newer than the project's oldest listed version, so it marks what's new rather than every page.
  • A doc removed in the current version stays routable (old links keep working) but disappears from navigation, search and the sitemap; it's only visible in older versions.
  • Don't delete a doc that a supported version still documents. Set removed: <version> instead. Deleting it makes it vanish from the older version too.
  • Release notes (releases/vX.Y.Z.md) use the version they describe as since.

npm run new:doc fills since with the project's current version. npm run docs:check reports a missing since, or one newer than the current version.


4. Release a new version of a product

Do this before editing docs for the new version, on a clean main:

bash
npm run docs:release -- gitaiflow 1.2.0 --notes      # dry run: shows the plan
npm run docs:release -- gitaiflow 1.2.0 --notes --write
git push origin gitaiflow/v1.1.3                      # push the tag it made

docs:release does the mechanical part:

  1. Freezes the version being replaced: tags the docs as they are now (gitaiflow/v1.1.3). Skipped when that version is built from a ref, or with --no-tag.
  2. Updates project.json: 1.2.0 becomes current, 1.1.3 becomes supported. --eol 1.1.1 marks an older version end-of-life.
  3. With --notes, writes releases/v1.2.0.md from the release-notes template, with since: 1.2.0.

It refuses when projects/<slug> has uncommitted changes (the tag would not match the docs), never moves an existing tag, and rejects a version that isn't newer or uses a different style (1.2 vs 1.2.0).

Then:

  1. Commit (docs(gitaiflow): release 1.2.0).
  2. Edit the docs for 1.2.0. New docs: npm run new:doc (since defaults to 1.2.0). Docs that go away: removed: 1.2.0.
  3. Merge to main. The site rebuilds.

To tag the current version without releasing anything (for example to freeze 1.1.3 today): npm run docs:release -- gitaiflow --freeze --write.

Which ref for which version

The common industry approach (Read the Docs, Antora):

Version status Build it from
current main (the normal docs)
supported A filtered view while text is shared; a maintenance branch ("ref": "release/1.1") once its wording diverges and still gets fixes
eol A tag: frozen, never changes

To start a maintenance branch: git branch release/1.1 gitaiflow/v1.1.3 && git push origin release/1.1, then add "ref": "release/1.1" to that entry.


5. Frozen versions in the build

Each version with a usable ref is exported with git archive and built like normal content under /projects/<slug>/v/<id>/….

  • Links between pages of a version stay inside that version.
  • Pages of an older version are canonical to the same page in the latest docs, or noindex when there isn't one, and are left out of sitemap.xml.
  • A version with no ref is a filtered view, silently. A version whose entry names a ref that can't be found falls back to a filtered view and warns.
  • Broken links inside an old ref are warnings, never build failures.

CI requirements

Dates and older versions need git history, tags and branches:

  • GitLab: set GIT_DEPTH: 0 (full clone). The build also tries git fetch --unshallow --tags, git fetch --tags and, for a branch ref, git fetch origin <branch> on its own.
  • Skip those automatic fetches with DOCS_NO_UNSHALLOW=1 and DOCS_NO_FETCH_TAGS=1.

Warnings

npm run build and npm run check-content print one grouped list of warnings, including explicit refs that fell back to filtered views. See RELEASING.md section 6.