# Skill: Releases Manage GitHub releases — create, edit, delete, upload assets, and manage release lifecycle. ## Commands Reference ### List Releases ```bash # List recent releases gh release list --limit 10 # JSON output with specific fields gh release list --json tagName,name,isDraft,isPrerelease,publishedAt --limit 10 # Exclude drafts and pre-releases gh release list --exclude-drafts --exclude-pre-releases --json tagName,name,publishedAt # List in a specific repo gh release list -R owner/repo --limit 5 ``` ### View a Release ```bash # View latest release gh release view --json tagName,name,body,assets,publishedAt,author,isDraft,isPrerelease # View specific release by tag gh release view v1.2.3 --json tagName,name,body,assets,publishedAt # Just the release notes gh release view v1.2.3 --json body --jq '.body' # List assets for a release gh release view v1.2.3 --json assets --jq '.assets[] | "\(.name) (\(.size) bytes) - \(.downloadCount) downloads"' ``` ### Create a Release ```bash # Basic release from existing tag gh release create v1.0.0 --title "v1.0.0" --notes "First stable release" # Create release and tag (tag doesn't need to exist yet) gh release create v1.2.0 --title "v1.2.0 - Performance improvements" --notes "## What's Changed - 50% faster startup time - Reduced memory usage by 30% - Fixed database connection leak (#42)" # Auto-generate release notes from PRs/commits gh release create v1.3.0 --generate-notes # Auto-generate with custom title gh release create v1.3.0 --title "v1.3.0" --generate-notes # Pre-release gh release create v2.0.0-beta.1 --title "v2.0.0 Beta 1" --prerelease --notes "Beta release for testing" # Draft release (not visible to public) gh release create v1.4.0 --draft --title "v1.4.0" --notes "Draft - do not publish yet" # Target a specific commit/branch (not HEAD) gh release create v1.2.1 --target hotfix/critical-fix --title "v1.2.1 Hotfix" --notes "Critical security patch" # Release notes from file gh release create v2.0.0 --title "v2.0.0" --notes-file ./CHANGELOG.md # With binary assets attached gh release create v1.0.0 \ --title "v1.0.0" \ --notes "First release" \ ./dist/app-linux-amd64 \ ./dist/app-darwin-amd64 \ ./dist/app-windows-amd64.exe # Assets with custom labels gh release create v1.0.0 \ --title "v1.0.0" \ --generate-notes \ './dist/app-linux-amd64#Linux (amd64)' \ './dist/app-darwin-amd64#macOS (amd64)' \ './dist/app-windows-amd64.exe#Windows (amd64)' # Mark as latest (explicit) gh release create v1.5.0 --title "v1.5.0" --latest --generate-notes # Do NOT mark as latest (e.g., patching an older major version) gh release create v1.2.5 --title "v1.2.5" --latest=false --notes "Backport security fix" # Set discussion category (creates a linked discussion) gh release create v2.0.0 --title "v2.0.0" --generate-notes --discussion-category "Announcements" ``` ### Edit a Release ```bash # Update title gh release edit v1.0.0 --title "v1.0.0 - Initial Release" # Update notes gh release edit v1.0.0 --notes "Updated release notes with additional details" # Change from draft to published gh release edit v1.4.0 --draft=false # Mark/unmark as pre-release gh release edit v2.0.0-beta.1 --prerelease=false gh release edit v2.1.0 --prerelease # Change latest designation gh release edit v1.5.0 --latest # Change target commitish gh release edit v1.0.0 --target main # Update tag name gh release edit v1.0.0 --tag v1.0.1 ``` ### Delete a Release ```bash # Delete release (keeps the git tag) gh release delete v1.0.0-beta --yes # Delete release AND the associated git tag gh release delete v1.0.0-beta --yes --cleanup-tag ``` ### Upload Assets ```bash # Upload asset to existing release gh release upload v1.0.0 ./dist/app-linux-amd64 # Upload multiple assets gh release upload v1.0.0 ./dist/app-linux-amd64 ./dist/app-darwin-amd64 ./dist/checksums.txt # Upload with custom label gh release upload v1.0.0 './dist/app-linux-amd64#Linux binary (x86_64)' # Overwrite existing asset with same name gh release upload v1.0.0 ./dist/app-linux-amd64 --clobber ``` ### Download Assets ```bash # Download all assets from latest release gh release download # Download from specific release gh release download v1.0.0 # Download specific asset by name pattern gh release download v1.0.0 --pattern "*.tar.gz" gh release download v1.0.0 --pattern "app-linux-*" # Download to specific directory gh release download v1.0.0 --dir ./downloads # Download from another repo gh release download v1.0.0 -R owner/repo --pattern "*.zip" # Skip existing files gh release download v1.0.0 --skip-existing ``` ## Workflows ### Standard Release Workflow ```bash # 1. Check what's changed since last release LAST_TAG=$(gh release view --json tagName --jq '.tagName') echo "Changes since $LAST_TAG:" git log "$LAST_TAG"..HEAD --oneline # 2. Create the release with auto-generated notes gh release create v1.5.0 \ --title "v1.5.0" \ --generate-notes # 3. Verify the release gh release view v1.5.0 --json tagName,name,publishedAt,isDraft ``` ### Release with Build Artifacts ```bash # 1. Build artifacts make build-all # produces binaries in ./dist/ # 2. Generate checksums cd dist && sha256sum * > checksums.txt && cd .. # 3. Create release with all artifacts gh release create v2.0.0 \ --title "v2.0.0 - Major Release" \ --generate-notes \ --discussion-category "Announcements" \ ./dist/app-linux-amd64 \ ./dist/app-darwin-amd64 \ ./dist/app-darwin-arm64 \ ./dist/app-windows-amd64.exe \ ./dist/checksums.txt ``` ### Draft Release Workflow Prepare a release in advance, then publish when ready: ```bash # 1. Create draft as work progresses gh release create v2.0.0 \ --draft \ --title "v2.0.0 - Next Major" \ --notes "## Highlights - Feature A - Feature B - Breaking change: X" # 2. Upload assets as they're built gh release upload v2.0.0 ./dist/app-linux-amd64 --clobber # 3. When ready, publish gh release edit v2.0.0 --draft=false ``` ### Hotfix Release (Backport) ```bash # 1. Create from a maintenance branch, not latest gh release create v1.4.1 \ --target release/1.4 \ --title "v1.4.1 - Security Patch" \ --notes "Backports critical security fix from v2.x. See #189." \ --latest=false # 2. Verify it didn't override "latest" gh release list --limit 3 --json tagName,isLatest ``` ### Pre-release to Stable Promotion ```bash # 1. Release as pre-release for testing gh release create v3.0.0-rc.1 \ --prerelease \ --title "v3.0.0 Release Candidate 1" \ --generate-notes # 2. After validation, promote to stable gh release edit v3.0.0-rc.1 --prerelease=false --tag v3.0.0 --title "v3.0.0" # OR create a fresh stable release gh release create v3.0.0 \ --title "v3.0.0" \ --generate-notes \ --discussion-category "Announcements" ``` ### Changelog-Based Release ```bash # Extract latest section from CHANGELOG.md and use as notes gh release create v1.6.0 \ --title "v1.6.0" \ --notes-file <(sed -n '/^## \[1\.6\.0\]/,/^## \[/{ /^## \[1\.6\.0\]/d; /^## \[/d; p; }' CHANGELOG.md) ``` ## Auto-Generated Release Notes Configuration GitHub can auto-categorize PRs in release notes. Configure via `.github/release.yml`: ```yaml # .github/release.yml changelog: exclude: labels: - ignore-for-release authors: - dependabot categories: - title: Breaking Changes labels: - breaking-change - title: New Features labels: - enhancement - feature - title: Bug Fixes labels: - bug - fix - title: Documentation labels: - documentation - title: Dependencies labels: - dependencies - title: Other Changes labels: - "*" ``` ## Available JSON Fields Use these with `--json` on `gh release view` / `gh release list`: `apiUrl`, `assets`, `author`, `body`, `createdAt`, `databaseId`, `id`, `isDraft`, `isLatest`, `isPrerelease`, `name`, `publishedAt`, `tagName`, `tarballUrl`, `targetCommitish`, `uploadUrl`, `url`, `zipballUrl` Asset fields (nested): `apiUrl`, `contentType`, `createdAt`, `downloadCount`, `id`, `label`, `name`, `size`, `state`, `updatedAt`, `url` ## Tips - Use `--generate-notes` for most releases — it pulls from merged PRs since the last release and respects `.github/release.yml` categories. - Use `--latest=false` when releasing patches for older major versions to avoid overriding the "Latest" badge. - Draft releases are invisible to the public and useful for preparing releases incrementally. - Asset labels (the `#Label` syntax) make download pages more user-friendly. - Use `--clobber` with `gh release upload` in CI to handle re-runs gracefully. - `--discussion-category` creates an announcement discussion linked to the release — great for major versions. - Always use `--notes-file` for long release notes to avoid shell quoting issues.