Tags and releases
Intermediate GitHub UI
Why this matters
Release notes are often a documentation person's job and they are the one artefact users read. GitHub can draft them for you, which is a good start and a bad finish: the generated list is written in the team's language, not the user's.
Tag, then release
A tag is Git's permanent name for a commit (command page). A release is GitHub's page built on top of one, with notes, dates and downloadable assets.
| Tag | Release | |
|---|---|---|
| Belongs to | Git | GitHub |
| Is | a name for a commit | a page describing what that commit contains |
| Created by | git tag and a push, or while drafting a release |
Releases → Draft a new release, or a workflow |
| Visible to | anyone who clones | anyone who can see the repository |
Every release has a tag; not every tag has a release. Drafting a release can create the tag at the same time, which is how most teams do it.
Drafting one
From the repository page, Releases in the sidebar, then Draft a new release:
| Field | What to put |
|---|---|
| Choose a tag | An existing tag, or type a new one such as v1.3.0 to create it |
| Target | The branch or commit the new tag should mark, usually main |
| Release title | The version, optionally with a short theme |
| Describe this release | The notes; Markdown, with Generate release notes to start |
| Attach binaries | Files users download, dragged in |
| Set as a pre-release | Mark it unfinished, so tooling ignores it |
| Set as the latest release | Which version the repository advertises |
Then Publish release, or Save draft to finish later.
Generate release notes lists the merged pull requests since the previous release, with their authors, plus a new-contributors section and a full-changelog link. That is an excellent completeness check and a poor set of notes: pull request titles describe changes to the code, and users want to know what changed for them.
What to write
Keep the generated list, and put prose above it:
## What's new
- The trail list can be filtered by difficulty: `--difficulty hard`.
- The installation guide now covers Windows.
## Fixed
- The list no longer crashes when a trail has no distance (#15).
## Upgrading
No action needed. If you scripted the old `--level` option, it is now `--difficulty`.Three sections cover most releases: what is new, what is fixed, and anything the reader must do. A repository can also carry .github/release.yml to group the generated list by label, which is worth setting up once if you write notes often.
Finding out what shipped
| Question | Where |
|---|---|
| Which pull requests are in this release? | Generate release notes, or the compare view |
| What changed between two versions? | github.com/<owner>/<repo>/compare/v1.2.0...v1.3.0 |
| Which commits exactly? | git log --oneline v1.2.0..v1.3.0 |
| Does version X contain commit Y? | git tag --contains <hash> |
$ git fetch --tags
$ git log --oneline v1.2.0..mainThat range is the honest list of what has accumulated since the last release, and it is where notes start.
How to do it
Tags are Git; releases are not:
$ git tag -a v1.3.0 -m "Release 1.3.0: Windows FAQ and licence wording"
$ git push origin v1.3.0To https://github.com/northwind-trails/trailguide.git
* [new tag] v1.3.0 -> v1.3.0A plain git push does not send tags. With GitHub's gh tool, gh release create v1.3.0 --generate-notes does the whole thing from the terminal.
Git: Create Tag in the Command Palette, then Git: Push (Follow Tags). Releases are a web feature; the GitHub extension does not draft them.
Git → New Tag…, or right-click a commit in the Log → New Tag…, then tick Push Tags when pushing.
The same two-step idea: a tag, then a release under Deploy → Releases → New release, with milestones instead of generated pull request lists. See lesson 9.9.
- Releases → Draft a new release.
- Choose a tag: pick one, or type a new version and confirm creating it on the Target branch.
- Generate release notes, then rewrite the top of it in the user's language.
- Tick Set as a pre-release or Set as the latest release as appropriate.
- Attach any downloads, then Publish release.
Common mistakes
- Publishing the generated notes unedited. They are a changelog for the team, not notes for users.
- Assuming
git pushsends tags. It does not. - Moving a published tag to fix a release. Everyone who fetched it keeps the old one; ship a new version.
- Forgetting the upgrade note when something a user depends on changed.
- Marking a real release as a pre-release, so tools that follow "latest" never see it.
Try it yourself
Goal: cut a release and write notes worth reading.
- Make two small commits on
mainin your practice repository. - Releases → Draft a new release, type
v1.3.0as a new tag onmain. - Click Generate release notes and read what it produced.
- Write two sentences above it under "What's new", in the language a user would use.
- Publish, then run
git fetch --tagsandgit log --oneline v1.3.0locally to confirm the tag exists.
Expected result: a release page with your prose above the generated list, and a tag your clone can see after fetching.
Show solution
Step 3 and step 4 together are the lesson. The generated list is derived from pull request titles, which are written for reviewers; your two sentences are the translation. Keeping both serves both audiences and costs five minutes.