Three issues addressed together:
1. Race condition (was PR #56): changelog job now CREATES the Gitea
release rather than assuming build jobs have already created it.
Build jobs continue to use create-or-skip + upload unchanged.
2. Detached HEAD push: 'git push origin master' fails when HEAD is
detached (no local branch named master). Changed to 'HEAD:master'.
3. git-cliff tag guard: verify tag is present locally before running
git-cliff, to fail fast with a clear message rather than silently
generating a wrong changelog.
4. git commit idiom: replaced 'git commit || echo' (swallows all
non-zero exit codes including real failures) with an explicit
'git diff --staged --quiet' guard so set -euo pipefail is not
undermined.
The changelog job checks out a specific SHA (detached HEAD) then
commits CHANGELOG.md and tries to push with 'git push origin master'.
Since there is no local branch named 'master', git rejects the push
with 'src refspec master does not match any'.
Fix: use 'git push origin HEAD:master' which explicitly maps the
current detached HEAD to the remote master branch regardless of
local branch state.
Addresses the review warning: git rev-parse confirms the tag is
present in the local repo after git fetch --tags before git-cliff
or git tag --sort= runs against it. Fails fast with a clear error
if the tag is missing rather than silently generating an incomplete
changelog.
The changelog and build-* jobs all fan out from autotag in parallel.
Build jobs create the Gitea release with 'curl ... || true', but the
changelog job was trying to GET the release before any build job had
run, reliably failing with 'Could not find release for tag vX.Y.Z'.
Fix: changelog job owns release creation. It creates the release with
the git-cliff body if it does not exist, or patches the body if a
prior run already created it. Build jobs continue using their existing
create-or-skip + upload pattern unchanged.