docouture new --flow offers two shapes — decided at scaffold time, switchable later
with docouture branch-model.
Trunk-based — the default
One long-lived branch (main by default) plays both roles: it’s the branch Antora
tracks live as the prerelease version, and it’s the branch docouture-release.yml
requires, checks out, and cuts tags from. There is no second code path anywhere for
this — it’s the degenerate case where the two roles below happen to be the same
branch.
Git-flow
Two independently-named branches, e.g. develop and main:
-
prerelease branch (
develop) — whatantora-playbook.yml’s `content.sources[].branchesaggregates as the live prerelease version, and whatdocouture-publish-prerelease.ymlwatches (pushes to it republish automatically). -
release branch (
main) — whatdocouture-release.ymlrequires/checks out/pushes bump commits to, and whatdocouture-release-preview.ymlwatches (pull requests targeting it get a release preview comment).
Adopting git-flow maps directly onto the existing "merge a docs/release-labelled PR"
release trigger — no event change, only the branch name it’s filtered against.
Hotfix/release/* short-lived branches get no dedicated handling: they’re ordinary
feature-branch-shaped PRs into develop/main from docouture’s perspective, already
covered by the two roles above.
Which workflow watches which branch
| Workflow | Branch role it watches |
|---|---|
|
Neither — branch-agnostic, builds every PR’s own HEAD via
|
|
prerelease branch (push trigger) |
|
both, unconditionally (push trigger — see below;
also path-filtered to |
|
release branch (pull_request trigger) |
|
release branch (pull_request:closed + workflow_dispatch); under git-flow its |
|
Neither — never push-triggered, only |
docouture-kroki-cache-warm.yml triggers on both branches unconditionally, not just
one: GitHub’s cache-access rule only ever writes a trusted, cross-run cache entry from
a push to the repository’s actual configured default branch — and there’s no
reliable way to know at scaffold time which of the two a git-flow repo has set as
that. Warming both means whichever one really is the default gets its cache entry
written either way; the other branch’s push still produces a normal
base-branch-scoped cache, so nothing is wasted. (On a trunk-based site this
collapses to a single entry — both roles are the same branch.)
Both docouture-pr-verify.yml and docouture-kroki-cache-warm.yml are path-filtered to
docs/** + their own workflow file — neither has anything to usefully check or warm a
cache for from a change elsewhere in the repo. If docouture-pr-verify.yml is configured
as a required status check in branch protection, confirm that setup tolerates a skipped
run (GitHub’s "Do not require status checks on creation," or rulesets' own equivalent):
a PR that never touches docs/ now means it never reports at all, rather than reporting
green.
A release under git-flow, end to end
-
Feature branch →
develop:docouture-pr-verify.ymlfires on the PR if it touchesdocs/**(it’s branch-agnostic, but path-filtered — see above). On merge,docouture-publish-prerelease.ymlrepublishes the prerelease docs fromdevelop. -
develop→main, labelleddocs/release:docouture-pr-verify.ymlfires under the samedocs/**path filter, anddocouture-release-preview.ymlnow fires too (targetsmain), posting a preview comment. On merge,docouture-release.ymlcuts the release (checks outmain, tags it, pushes the tag) and callsdocouture-publish.ymlto build and publish. A versioned release also bumpsdocs/.release-versiononmain; itssync-prereleasejob then opens a pull request intodevelopcarrying that bump (branchautomated/sync-docs-release-<version>-to-develop) — merge it sodevelopdoesn’t go stale. It runs before the publish, which doesn’t wait on its result: a failed sync turns the run red but the docs still publish. -
The merge to
mainis also an ordinary push — butdocouture-publish-prerelease.ymldoes not fire a second time: its trigger isdevelop-only, so there’s no overlap with `docouture-release.yml’s own publish. (Under trunk-based, where both roles are the same branch, this same-push double-trigger risk is real, and `docouture-release.yml’s own header comment documents the mitigation.)
antora-playbook.yml’s `content.sources[] never lists the release branch
Only the prerelease branch appears under branches: — the release branch is never a
live, content-tracked branch, only the checkout target docouture-release.yml cuts
tags from. A tag is just a pointer to a commit; Antora’s tags: matcher doesn’t care
which branch produced it. So docs/stable/docs/vX.Y.Z genuinely reflect whatever was
on the release branch each time a release was cut, even though the release branch
itself is never named in the playbook. See Versioning modes
for what tags: is set to in each versioning mode.
Switching later: docouture branch-model
$ docouture branch-model git-flow --integration-branch develop
$ docouture branch-model trunk-based --branch main
Trunk-based → git-flow: the current single branch becomes the release branch by
default (least disruption to anything already tagged off it) — --integration-branch
(the new prerelease branch) is required, since there’s nothing on disk to infer that
name from.
Git-flow → trunk-based: lossy — --branch is required and must match one of the two
current branches exactly; a third, invented name is refused.
Either direction re-renders .github/workflows/ (the same machinery docouture
upgrade uses) and patches antora-playbook.yml’s `content.sources[0].branches and
docs/package.json’s `docouture.branching field. It does not rename actual git
branches, touch branch-protection/ruleset rules, or change GitHub’s configured default
branch — those stay manual steps, printed as a reminder after every real run.
The docouture block in docs/package.json declares the flow
"docouture": { "branching": "trunk-based" }
"docouture": { "branching": "git-flow", "prereleaseBranch": "develop" }
docouture-release.yml reads this block to know whether to open the prerelease sync
pull request (see above) and which branch to target — the only place the workflow reads
the flow from. Trunk-based declares branching only; git-flow also declares
prereleaseBranch. docouture new, docouture branch-model and docouture upgrade
keep it in step with antora-playbook.yml’s `content.sources[0].branches (what Antora
actually builds from): upgrade writes or corrects it on a git-flow site, which also
backfills sites scaffolded before the field existed. The release branch name is not
stored — it’s the checkout ref: in docouture-release.yml.
docouture doctor compares the declaration against what the playbook and workflow
actually say: a git-flow site without prereleaseBranch, or with a stale one, is reported
with docouture upgrade as the fix. A hand-edited playbook leaves the declaration stale
until upgrade (or branch-model) runs again.
Which one to pick
Trunk-based if one branch is genuinely enough — most sites. Git-flow if the
repository this docs site lives alongside already reserves main for
release/hotfix merges and uses develop as its integration branch — matching the
docs site’s branching to the code’s avoids a confusing mismatch between the two.