Skip to main content
ANVISoftware Solutions
Lesson 12 of 15Intermediate14 min

Stashing, Tagging and Releases

By the end of this lesson

Set work aside temporarily and mark released versions.

Two tools that look unrelated and solve adjacent problems. Stashing sets unfinished work aside so you can do something else. Tagging puts a permanent, human-readable name on a commit so you can find it again years later.

One is for the next twenty minutes. The other is for the next five years.

Setting work aside and picking it up again
Shell
# Something urgent has come up and your work is half-finished
git stash push -m "Half-done CSV export, missing header row"

# Your working directory is now clean
git status

# Deal with the urgent thing, then come back
git stash list

# Restore the most recent stash and remove it from the list
git stash pop

# Or restore it and keep it stashed as well
git stash apply stash@{0}

# Include untracked files, which stash ignores by default
git stash push -u -m "New exporter class, not yet added"
  • git stash push records your uncommitted changes, then returns your working directory to the last commit. The -m message is optional and worth writing — an unlabelled stash is unidentifiable within a day.
  • git stash list shows the stack, newest first. The stash@{0} notation is how you refer to an entry.
  • pop restores and removes; apply restores and keeps. Use apply when you want to try the changes on a different branch without losing the stash if it goes badly.
  • Without -u, new files that Git does not track yet are left behind in your working directory. This catches people out: they stash, switch branch, and find an unexpected file sitting there.

Tags name a commit permanently

A tag is a name for one specific commit that does not move. A branch pointer advances as you work; a tag stays where it was put. That fixedness is the entire feature — six months after release 2.4.0, the tag still points at exactly what was shipped.

There are two kinds. A lightweight tag is a bare name pointing at a commit. An annotated tag is a stored object with its own author, date and message, and it can be signed. For anything that represents a release, use an annotated tag: you will want to know who created it and what it contained.

Tagging a release
Shell
# Annotated tag on the current commit
git tag -a v2.4.0 -m "Release 2.4.0 - expense export and charity VAT rate"

# Tag a commit you forgot to tag at the time
git tag -a v2.3.1 9f3c2a1 -m "Release 2.3.1 - invoice rounding fix"

# Tags are not pushed by default
git push origin v2.4.0

# What has been released?
git tag --list "v2.*"

# What exactly was in that release?
git show v2.4.0

# What changed since the last release?
git log --oneline v2.3.1..v2.4.0
  • -a makes it annotated. The message is a release note in miniature and is worth more than the version number alone.
  • You can tag any commit by naming its identifier, which matters when you realise after the fact that a release was never tagged.
  • git push sends branches, not tags. A tag that exists only on your machine helps nobody, and this is the step most often forgotten.
  • The last command is how release notes get written: every commit between two tags, in order.

Branches and tags are both names for commits, and they behave in opposite ways:

 BranchTag
Moves when you commitYes — it follows your workNo — it stays on the commit it named
What it is forWork in progress, a line of developmentA fixed point worth returning to, usually a release
Pushed by defaultYes, once an upstream is setNo — it must be pushed explicitly
Expected lifetimeDeleted once the work is mergedKept indefinitely
Changing it after sharingNormal — that is what branches doAvoid. Others rely on it meaning one thing

Summary

  • git stash sets uncommitted work aside and gives you a clean working directory
  • Stash ignores untracked files unless you pass -u, which is the usual source of confusion
  • Stash is for hours, not weeks — anything longer belongs on a branch as a commit
  • A tag is a fixed name for one commit; use annotated tags for releases so the author and message are recorded
  • Tags are not pushed with your branches and must be pushed explicitly

Practice

Attempt each one before opening the solution. Getting it wrong first is how the idea sticks.

Try it yourself

Stash, switch, return

Make an uncommitted change and also create a brand new file. Stash with a message, then run git status.

Notice what is still there. Then restore the stash and confirm you have your change back.

Show solution

Your edit to the tracked file is gone from the working directory and safely in the stash. The new file is still sitting there, because stash ignores untracked files unless you pass -u.

That asymmetry is the one piece of stash behaviour worth remembering. Most surprises with stash come from it.

Shell
git stash push -m "Partial rate-limit work"
git status          # the new file is still listed as untracked
git stash pop

# To include it next time
git stash push -u -m "Partial rate-limit work, with new files"

Think about it

Think about it

A customer reports a bug in version 2.3.0, which was released four months ago. Main has moved on by two hundred commits.

What does the tag let you do that a commit identifier written in a document would not?

Show solution

The tag is in the repository, so anyone can reach that exact state without finding the right document: git switch -c investigate-2.3.0 v2.3.0 gives them the released code.

It also makes comparison straightforward. git log v2.3.0..v2.4.0 lists what changed between releases, which is how you narrow down which change introduced a fault.

A commit identifier in a wiki page does the same thing in principle. It relies on the page still existing and being correct, which is a weaker guarantee than the repository itself.

Saved in this browser only.