Version your docs with branches
This how-to guide sets up versioned documentation the way Antora intends:
one git branch per documented version, with the playbook assembling all
of them into one site. No copied folders, no docs-v2-final/, and
backporting a fix to an older version is a cherry-pick.
It assumes a working component and playbook (from the tutorial) and a product that's about to ship a version worth freezing the docs for.
The model in one paragraph
The documented version of a component comes from the version key in
antora.yml — as it exists on each branch. The branch that holds today's
development docs says version: '2.0'; the branch you froze at the last
release says version: '1.0' in its copy of the same file. The playbook
lists which branches to read, Antora builds every component version it
finds, and the site's version selector appears on its own.
1. Decide what a "version" is
Document versions the reader chooses between, not every patch. If users run "Widget 1.4" and "Widget 2.0", those are your docs versions; 1.4.3 is not. Each docs version gets a long-lived branch in the content repository. Reuse your release branches if the product already maintains them, since docs fixes then ride the branch your team already backports code to.
2. Cut the version branch at release
When Widget 1.0 ships, freeze its docs by creating the branch (if your release process hasn't already):
cd widget
git switch -c v1.0 main
git push -u origin v1.0
The antora.yml on this branch already says version: '1.0', so there's
nothing to edit here. This branch now receives only fixes that apply to 1.0.
3. Roll main forward to the next version
On main, update the descriptor so development docs stop claiming to be
1.0. While you're in the file, mark the unreleased version as a prerelease:
name: widget
title: Widget
version: '2.0'
prerelease: true
nav:
- modules/ROOT/nav.adoc
prerelease: true keeps 2.0 out of the "latest" slot: it still builds and
appears in the version selector (labeled as a prerelease), but links that
point at the component's latest version keep resolving to 1.0 until 2.0
actually ships. At ship time, cut v2.0 from main, delete the
prerelease line on the new branch, and bump main to '2.1' — that's the
whole release ritual.
4. Tell the playbook which branches to read
In antora-playbook.yml, widen the content source from one branch to a
pattern:
content:
sources:
- url: https://github.com/your-org/widget.git
branches: [main, v*]
start_path: docs
branches accepts exact names and globs; [main, v*] reads the development
docs plus every version branch you've cut. Rebuild, and the site now serves
/widget/1.0/ and /widget/2.0/ side by side with a working version
selector — that's the entire feature.
5. Backport a fix
A reader reports that the 1.0 install page documents the wrong flag, and the
mistake is still present on main. Fix it once, then backport:
git switch main
# edit, commit via the normal pull-request flow
git switch v1.0
git cherry-pick <commit-sha>
git push
The next site build publishes the correction in both versions. This is the payoff of versions-as-branches: the operation you already trust for code works unchanged for docs, review included if you prefer a pull request over a direct cherry-pick.
NOTE: If a fix applies only to an old version (say, 1.0-specific
behavior), commit it directly to v1.0 and skip main. Branches are
independent; nothing forces changes to flow through the development branch.
6. Retire a version
When 1.0 leaves support, stop publishing its docs by removing it from the playbook, not by deleting the branch:
branches: [main, v*, "!v1.0"]
The negated pattern excludes the branch from builds while the branch itself (and its history) stays in the repository, ready if you ever need to republish or consult it. Deleting docs history to unpublish a page is the wiki reflex; you don't need it anymore.
Common mistakes
- Unquoted versions.
version: 2.0is a YAML float and will bite you as'2'somewhere downstream. Always quote:version: '2.0'. - Fixing docs only on
main. Readers of 1.0 never see it. Make "does this need a backport?" a standard pull-request question for docs, same as for code. - A version branch nobody can find. Name docs version branches exactly like the product's release branches, or document the mapping in the component's CONTRIBUTING notes.
- Versioning pages that don't version. Release notes or a glossary that
should always show the latest content can live in a separate unversioned
component (
version: ~) instead of being backported forever.
Related pages
- antora.yml and playbook keys, annotated:
version,prerelease,display_version, and thebranchespatterns in one place. - How Antora assembles a site: why reading versions out of git branches is the design center of the whole tool.