Git & Command Line · Lesson 10 of 12
Stash, Tags and Releases
Use git stash to park unfinished work, create annotated tags for versions, follow semantic versioning and publish GitHub Releases from your tags.
- Intermediate
- 14 min read
- 4 objectives
Before this lessonLesson 9: Undoing Things and Team Workflows
What you will learn
- Stash tracked and untracked changes and restore them
- Manage several stashes
- Create, push and delete annotated tags
- Version releases with SemVer and GitHub Releases
Your Progress
0 of 12 lessons 0%
- Lessons0 / 12
- Completed0
- Est. time left~ 3 hours
Create a free account to keep your progress on every device.
Tip: pressing Next marks this lesson complete automatically.
Two features that look unrelated but share a theme: bookmarking. Stash bookmarks unfinished work so you can switch context. Tags bookmark a finished commit forever, usually a release. The undo lesson showed the basic stash commands; here we go further and connect tags to real releases on GitHub.
Stash in more detail
A stash is a hidden commit holding your uncommitted changes. By default it only saves tracked files. Add -u to include untracked (new) files too, which is almost always what you want:
echo wip >> app.txt; touch new.txt
git stash push -u -m "wip: login form"
git status --short
git stash listSaved working directory and index state On main: wip: login form
stash@{0}: On main: wip: login formgit status --short printed nothing: the working tree is clean and you can switch branches, pull, or fix an urgent bug. To look inside a stash before restoring it:
git stash show -p stash@{0}diff --git a/app.txt b/app.txt index 626799f..70c5f1c 100644 --- a/app.txt +++ b/app.txt @@ -1 +1,2 @@ v1 +wip
pop, apply and drop
git stash pop: re-apply the newest stash and delete it from the list.git stash apply stash@{1}: re-apply a specific stash but keep it in the list (useful to apply to several branches).git stash drop stash@{1}: delete one stash;git stash cleardeletes all of them.git stash branch fix-login stash@{0}: create a new branch from where the stash was made and apply it there, which avoids conflicts.git stash push -m "msg" -- src/login.js: stash only specific paths.
git stash popOn branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: app.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
new.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (f9e2c61e6f5ee088835c6768aa9da02e4dbcff4d)Tags: permanent names for commits
A branch pointer moves with every commit; a tag stays put. That makes tags perfect for marking "this exact commit is version 1.0.0". There are two kinds:
- Lightweight: just a name,
git tag v1.1.0-beta. Fine for private bookmarks. - Annotated: a full object with tagger, date and message,
git tag -a v1.0.0 -m "...". Use these for releases; many tools (includinggit describe) prefer them.
git tag -a v1.0.0 -m "Version 1.0.0" HEAD~1 # tag an older commit
git tag v1.1.0-beta # lightweight, on HEAD
git tag -l
git show v1.0.0 --stat | head -8v1.0.0 v1.1.0-beta tag v1.0.0 Tagger: Ada <ada@stackcone.com> Date: Wed Sep 23 10:09:04 2026 +0530 Version 1.0.0 commit e4f486beed43f592dcbd14500341a228d673fa40 Author: Ada <ada@stackcone.com>
git describe --tags names the current commit relative to the nearest tag (for example v1.0.0-3-g9f8e7d6, meaning three commits after v1.0.0), which is handy for build version strings.
Sharing and deleting tags
git push does not send tags by default. Push them explicitly:
git push origin v1.0.0 # one tag
git push --follow-tags # annotated tags reachable from pushed commits
git tag -d v1.1.0-beta # delete locally
git push origin --delete v1.1.0-beta # delete on the remote
git fetch --tags # get tags others pushed
git switch --detach v1.0.0 # look at the code as it was at v1.0.0Semantic versioning
Most projects name tags with SemVer: vMAJOR.MINOR.PATCH.
- PATCH (1.0.0 to 1.0.1): bug fixes only.
- MINOR (1.0.1 to 1.1.0): new features, still backward compatible.
- MAJOR (1.1.0 to 2.0.0): breaking changes that need users to update their code.
- Pre-releases add a suffix:
2.0.0-beta.1,2.0.0-rc.1.
GitHub Releases
A GitHub Release is a tag plus release notes and optional downloadable files. You can create one from the web UI (Releases, Draft a new release) or with the GitHub CLI, which can also write the notes from merged pull requests:
git tag -a v1.2.0 -m "Version 1.2.0"
git push origin v1.2.0
gh release create v1.2.0 --generate-notes
gh release create v2.0.0-rc.1 --prerelease --title "2.0 RC 1" dist/app.zipIn the CI lesson you will see how pushing a tag like v1.2.0 can automatically build and publish a release.
Recap
git stash push -u -mparks all changes, including new files.poprestores and deletes;applyrestores and keeps;stash branchavoids conflicts.- Use annotated tags for releases and push them explicitly.
- Name versions with SemVer and never move a published tag.
gh release create --generate-notesturns a tag into a GitHub Release.
# Write your solution here
Finished reading? Mark this lesson complete to track your progress.
