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:write scope — deliberately separate from git:write, because publishing carries a different blast radius than linking.

Next steps

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.

Rebuild this step in your own workspace.

The guide takes a few minutes — it sticks when it is your own board underneath. 14 days of full access, no credit card.