Tutorial
Bind a release to a git tag
Versions that match reality: plan a release, bind it to the real git tag, and have its contents filled from the commit history automatically.
Last updated:
"What is actually in v2.3?" is an archaeology exercise in most teams. In Zuuna a release is bound to the real git tag, and its contents come from the commit history — not from memory. Releases belong to the Developer plan.
What you need
- The Developer plan — see pricing.
- An API token and the zuuna CLI already set up in the repository.
- A repository where versions exist as git tags (or should from today).
1. Get the tools ready
Everything runs through the CLI you know from commit linking — the same ./zuuna, the same .git/zuuna.conf.
2. Plan the release
./zuuna plan "v2026.08.1" --tag v2026.08.1 --date 2026-08-15
That creates a planned release. The tag is the key — not the name. The name may be "summer release"; matching happens on v2026.08.1.
3. Tag and push
git tag -a v2026.08.1 -m "v2026.08.1"
git push origin v2026.08.1
Nothing Zuuna-specific — your normal release move.
4. Send the manifest
./zuuna release --tag v2026.08.1
Now the interesting part: the CLI computes the commit range from the previous tag to this one on your machine and reports it as a manifest. Why locally? Because only your repository holds the full history — Zuuna stores no git ancestry and only knows commits that ever named a card key. For the very first release, pass the predecessor with --prev.
5. See what the release shows
The release now lists: the cards whose work lies in the range, the commits and merged pull requests — and, more honestly than most tools, the work that never named a ticket. That last list is exactly what you want to have seen before publishing.
6. Curate and publish
Cards can be added by hand — the cherry-pick, the backport, the docs change without a commit. Hand-picked cards stay, even when the manifest runs again: a second run against a published release repairs its data instead of re-publishing — so no webhooks fire twice either. Then publish. Subscribers to the RELEASE_PUBLISHED webhook hear about it immediately.
Troubleshooting
- "No predecessor tag found." First release — pass
--prev. - The release is empty. The range holds no commits naming card keys, or the tag was never pushed.
- A wrong tag. The tag is the match key — release tag and git tag must agree exactly.
- 401/403. The token needs the
releases:writescope — deliberately separate fromgit:write, because publishing carries a different blast radius than linking.
Next steps
- Set up a deploy target and approval gate — ship the release in one click.
- Read the code graph.
- Git on the board.
FAQ
Why does the CLI compute the commit range and not the server?
Because only your repository knows the full truth. Zuuna stores no git ancestry — it only knows commits that ever named a card key. The range between two tags can only be computed where the history lives: with you.
What about the very first release?
A range needs a predecessor. For the first release you pass it yourself with --prev — after that the CLI finds the previous tag on its own.
Can I do this from GitHub Actions?
Yes. Token as a secret, CLI in a workflow step — the manifest can be sent from the same pipeline that builds the tag.
Does the next run overwrite my hand-picked cards?
No. Cards added by hand stay. And re-running against a published release repairs its data rather than re-publishing it — so no webhooks fire twice either.
Which plan?
Releases belong to the Developer plan.