
Git Stash and Tags: Managing Temporary Work and Releases
Git stash and Git tags solve two very different problems.
A stash is temporary. It helps you set aside unfinished local changes, return to a cleaner working state, and restore the work later. A tag is persistent. It gives a stable name to an important Git object—usually a commit—so a team can identify a release, deployment, milestone, or historical checkpoint.
These commands are often introduced together because both preserve a reference to project state, but they should not be confused. Stashes are personal working tools that usually remain inside one local repository. Tags are repository references that are often shared with a team and used in release workflows.
This guide explains both features deeply. You will practice creating, inspecting, applying, removing, and recovering stashes; understand tracked, untracked, staged, and ignored-file behavior; resolve stash conflicts; create lightweight and annotated tags; tag historical commits; inspect and verify tags; publish tags safely; and avoid dangerous retagging mistakes.
What You Will Learn
What Git stash records and when it is appropriate.
The difference between
stash push,apply, andpop.How staged, unstaged, untracked, and ignored files affect a stash.
How to stash selected paths or selected hunks.
How to preserve the index with
--keep-index.How to stash only staged changes.
How to inspect, rename conceptually, branch from, drop, and clear stashes.
How stash conflicts occur and how to resolve them.
What lightweight, annotated, and signed tags represent.
How tags differ from branches.
How to tag an older commit.
How to list, filter, sort, inspect, delete, and replace tags.
How to push individual tags and selected release tags.
Why changing a published tag is dangerous.
How tags support release and deployment workflows.
Part One: Understanding Git Stash
Git stash records the current state of selected working-tree and index changes, then normally restores those areas toward the state represented by HEAD.
A common scenario looks like this:
You are halfway through a feature.
An urgent fix requires switching to another branch.
The current changes are not ready for a meaningful commit.
The target branch cannot be checked out safely with the current working tree.
You stash the unfinished work, handle the urgent task, then restore the work later.
The simplest command is:
git stash pushThe shorter historical form is:
git stashFor modern, explicit workflows, git stash push is clearer because it accepts messages, pathspecs, and selection options.
A Stash Is Not a Normal Branch or Commit
A stash is represented internally through Git objects and commit-like structures, but it is managed through a special reference and reflog rather than as an ordinary development branch.
Stashes normally appear in a stack-like list:
stash@{0}
stash@{1}
stash@{2}stash@{0} is usually the most recent stash.
A stash should not become a permanent storage system for important work. Long-lived, meaningful development is usually safer on a branch with understandable commits.
When Should You Use Git Stash?
Stash is useful when:
You must switch branches temporarily.
You need a clean working tree before pulling, rebasing, or testing.
You want to compare current work against a clean project state.
You have unrelated local edits that should not enter the next commit.
You are about to perform a risky operation and want a short-lived local checkpoint.
You want to move unfinished changes onto a new branch.
Stash is less appropriate when:
The work is already a meaningful checkpoint that can be committed.
The work must be shared with another developer.
The changes need reliable long-term preservation.
You have many old stashes with unclear messages.
You are using stash to avoid organizing commits and branches.
Create a Practice Repository
The examples use a small project called Task Notes.
macOS, Linux, or Git Bash
mkdir git-stash-tags-demo
cd git-stash-tags-demo
git init -b main
cat > app.txt <<'EOF'
Task Notes
Storage: local
Search: disabled
EOF
cat > README.md <<'EOF'
# Task Notes
A small project for practicing Git stash and tags.
EOF
git add app.txt README.md
git commit -m "Create task notes project"
PowerShell
New-Item -ItemType Directory git-stash-tags-demo
Set-Location git-stash-tags-demo
git init -b main
@"
Task Notes
Storage: local
Search: disabled
"@ | Set-Content app.txt
@"
# Task Notes
A small project for practicing Git stash and tags.
"@ | Set-Content README.md
git add app.txt, README.md
git commit -m "Create task notes project"
Verify the starting point:
git status
git log --onelineCreate Your First Stash
Modify app.txt:
Task Notes
Storage: local
Search: keyword
Check the repository:
git status
git diffCreate a stash with a useful message:
git stash push -m "WIP: add keyword search"Inspect the status:
git statusThe tracked modification should normally be removed from the working tree, returning it to the current commit state.
List stashes:
git stash listExample:
stash@{0}: On main: WIP: add keyword searchThe exact output may include branch and commit context.
Always Add a Stash Message
Without a custom message, several stashes can become difficult to distinguish:
stash@{0}: WIP on main: ...
stash@{1}: WIP on main: ...
stash@{2}: WIP on main: ...A useful message describes the unfinished task:
git stash push -m "WIP: validate imported task dates"
git stash push -m "Debug: inspect slow report query"
git stash push -m "Experiment: new search result layout"The prefix is optional. What matters is that the message helps you recognize the work later.
Inspect a Stash
Show a summary of the latest stash:
git stash showShow the full patch:
git stash show -pInspect a selected stash:
git stash show -p stash@{1}Use a stat summary:
git stash show --stat stash@{0}Before applying an old stash, inspect its content. A message alone may not reveal every file it contains.
Apply vs Pop
Restore the latest stash while keeping it in the stash list:
git stash applyRestore a selected stash:
git stash apply stash@{1}Restore the latest stash and remove it from the list after a successful application:
git stash popPop a selected stash:
git stash pop stash@{1}| Command | Restores Changes | Removes Stash Automatically |
|---|---|---|
git stash apply | Yes | No |
git stash pop | Yes | After a successful application |
Use apply when you want a safer review step or need the same stash in more than one place. Use pop when you are confident the stash should be restored and removed.
When conflicts prevent a clean pop, Git normally keeps the stash so it is not lost automatically.
Does Stash Include Untracked Files?
By default, git stash push primarily saves tracked modifications and staged changes. Ordinary untracked files are not automatically included.
Create an untracked file:
echo "Temporary search notes" > search-notes.txtCheck:
git status --shortStash tracked and untracked changes:
git stash push -u -m "WIP: search implementation and notes"The long option is:
git stash push --include-untrackedAfterward, the untracked file should normally be removed from the working tree and stored with the stash.
Stashing Ignored Files
Ignored files are not included by -u.
To include ignored files as well:
git stash push -a -m "WIP: include generated local files"The long option is:
git stash push --allUse --all carefully. Ignored directories may contain:
Large dependency folders.
Build output.
Logs.
Local caches.
Generated assets.
Environment-specific files.
Stashing all ignored content can be slow and consume significant repository storage.
Staged and Unstaged Changes in a Stash
A file can contain staged and unstaged changes at the same time.
Example:
Edit
README.md.Run
git add README.md.Edit
README.mdagain.Run
git status --short.
You may see:
MM README.mdA normal stash can preserve both the index state and working-tree state. However, how they are restored depends on the apply options.
To attempt to restore the staged state as well:
git stash apply --indexOr:
git stash pop --indexWithout --index, the content may be restored without recreating the same staged arrangement.
Index restoration can fail when the current repository state no longer allows the original staging structure to be reconstructed cleanly.
Keep Staged Changes in Place
Sometimes you have a complete staged fix and additional unfinished working-tree changes. You want to stash only the unfinished part and keep the index ready to commit.
Use:
git stash push --keep-index -m "WIP: unfinished documentation edits"The staged changes remain available, while other suitable changes are stashed.
A practical workflow is:
git add fix.php
git stash push --keep-index -m "WIP: unrelated experiments"
git diff --staged
git commit -m "Fix invoice rounding"
git stash popAlways inspect the status after stashing. Options affect different repository layers, and mixed staged and unstaged versions require careful review.
Stash Only Staged Changes
When you want to stash the index content and leave other working-tree changes:
git stash push --staged -m "WIP: staged search implementation"This is useful when staged changes form one group that should be set aside while unstaged work remains visible.
Review before and after:
git status
git diff
git diff --staged
git stash push --staged -m "WIP: staged search implementation"
git statusIf staged and unstaged changes overlap in ways Git cannot separate safely, the operation may stop or require reorganizing the changes first.
Stash Selected Files
You do not need to stash the entire working tree.
Stash one file:
git stash push -m "WIP: README rewrite" -- README.mdStash several paths:
git stash push -m "WIP: search files" -- app.txt search-notes.txtStash a directory:
git stash push -m "WIP: report module" -- src/Report/The -- separates command options from pathspecs.
Path-limited stashing is useful when several independent tasks are mixed in one working tree, though separating work earlier through branches and commits is often cleaner.
Interactive Stashing with --patch
Stash selected hunks interactively:
git stash push -p -m "WIP: selected search changes"The long option is:
git stash push --patchGit displays hunks and asks whether each should be included.
Common responses include:
y: Include this hunk.n: Leave this hunk in the working tree.s: Split the hunk when possible.e: Edit the patch manually.q: Stop selecting.?: Display help.
Afterward, run:
git status
git stash show -p stash@{0}Confirm that the intended hunks entered the stash and the remaining edits stayed in the working tree.
Stash a Clean Working Tree?
If there are no suitable local changes, Git normally reports that there is nothing to save.
A stash is not a replacement for creating a named checkpoint of an already committed state. Use a branch or tag for that purpose.
Apply a Stash on Another Branch
A stash is not permanently tied to the branch where it was created.
You can switch branches and apply it:
git switch feature/search
git stash apply stash@{0}This can be useful when changes were started on the wrong branch.
However, applying the stash to a different codebase state increases the chance of conflicts. Inspect the branch difference and stash patch first.
Create a Branch from a Stash
When the current branch has changed significantly since the stash was created, applying it directly may cause conflicts.
Use:
git stash branch feature/search-recovery stash@{0}This command creates and checks out a new branch from the commit where the stash was originally created, applies the stash there, and drops the stash if the application succeeds.
This is one of the safest ways to turn an old stash into regular branch-based work.
Stash Conflicts
A stash application can conflict when the current files changed in ways incompatible with the stashed changes.
Example:
Stash a change to the
Storageline.Commit a different change to the same line.
Apply the old stash.
Git may insert conflict markers:
<<<<<<< Updated upstream
Storage: encrypted local
=======
Storage: cloud
>>>>>>> Stashed changesResolve the conflict like a merge conflict:
Run
git status.Open every conflicted file.
Understand the current and stashed intentions.
Edit the correct combined result.
Remove conflict markers.
Stage resolved files with
git add.Run tests.
Create a commit when the restored work reaches a meaningful state.
Unlike an active merge, stash application does not provide the same git merge --abort workflow. If recovery becomes unclear, protect current work before resetting or restoring files.
Drop One Stash
Delete a selected stash:
git stash drop stash@{1}Delete the latest stash:
git stash dropInspect the stash before dropping it:
git stash show -p stash@{1}After a drop, stash indices can change because the list is reflog-based. Run git stash list again before referring to another position.
Clear All Stashes
git stash clearThis removes all stash entries from the stash reference.
There is no interactive confirmation by default. Before clearing:
git stash list
git stash show -p stash@{0}
git stash show -p stash@{1}Important work should be converted into branches or commits rather than left in a stash list.
Recovering a Dropped Stash
A recently dropped stash may remain as unreachable Git objects for a limited time, but recovery is not guaranteed.
Possible investigation tools include:
git fsck --unreachable
git fsck --no-reflogsYou may identify dangling or unreachable commit-like objects and inspect candidates with:
git show <object-id>If the correct object is found, preserve it immediately:
git branch stash-recovery <object-id>Recovery depends on garbage collection, repository maintenance, and object reachability. Treat dropped or cleared stashes as potentially lost.
Advanced Stash Creation Commands
Most developers should use git stash push. Git also exposes lower-level stash operations.
Create Without Storing in the Stash List
git stash create "temporary stash object"This creates a stash-like commit object and prints its identifier without updating the normal stash reference.
Store an Existing Stash Object
git stash store -m "Recovered temporary work" <object-id>These commands are useful for scripts and recovery workflows but are easier to misuse than push.
Stash Best Practices
Use descriptive messages.
Inspect the working tree before stashing.
Use
-uonly when untracked files are required.Avoid
-aunless ignored files truly need preservation.Inspect a stash before applying or dropping it.
Prefer
applyoverpopwhen the situation is risky.Use
--indexonly when restoring the staged arrangement matters.Turn long-lived stashes into branches.
Do not use stash as a substitute for meaningful commits.
Clean old stashes after confirming they are no longer needed.
Part Two: Understanding Git Tags
A Git tag gives a readable name to a specific object, usually a commit.
Tags are commonly used for:
Software releases.
Production deployments.
Public milestones.
Compatibility baselines.
Important historical checkpoints.
Signed release references.
Unlike a branch, a tag does not move automatically when new commits are created.
Tag vs Branch
Assume both a branch and tag point to commit C:
A---B---C
^ main
^ v1.0.0Create a new commit on main:
A---B---C---D
^ ^
v1.0.0 mainThe branch moves to D. The tag remains at C.
| Branch | Tag |
|---|---|
| Moves as new commits are created | Normally remains fixed |
| Represents an active line of development | Marks a specific object or milestone |
| Usually checked out for ongoing work | Usually inspected or used as a release reference |
| Stored under branch references | Stored under tag references |
List Tags
List all tags:
git tagEquivalent list form:
git tag --listFilter by a shell-style pattern:
git tag --list "v1.*"List tags with annotation information when available:
git tag -nShow more message lines:
git tag -n3Lightweight Tags
A lightweight tag is a name that points directly to an object, commonly a commit.
Create one at the current commit:
git tag v0.1.0Inspect it:
git show v0.1.0A lightweight tag does not create a separate annotated tag object containing a tagger, date, and message.
Lightweight tags can be useful for:
Temporary local labels.
Private bookmarks.
Short-lived test markers.
Simple internal checkpoints.
For formal releases, annotated tags are usually more informative.
Annotated Tags
Create an annotated tag:
git tag -a v1.0.0 -m "Release version 1.0.0"An annotated tag creates a tag object containing metadata such as:
The tagged object reference.
The tag name.
The tagger name and email.
The creation date.
The annotation message.
An optional cryptographic signature when signing is used.
Inspect it:
git show v1.0.0The output normally includes the tag message and information about the referenced commit.
Lightweight vs Annotated Tags
| Feature | Lightweight Tag | Annotated Tag |
|---|---|---|
| Separate tag object | No | Yes |
| Tagger identity | No dedicated tagger metadata | Yes |
| Tag message | No | Yes |
| Creation date in tag object | No | Yes |
| Can carry a tag signature | No | Yes |
| Typical use | Temporary or private labels | Releases and important milestones |
Some Git commands prefer annotated tags by default because they represent explicit release-style tag objects.
Tag a Historical Commit
You do not need to tag only the current commit.
Find the target:
git log --onelineCreate an annotated tag on an older commit:
git tag -a v0.9.0 7a93c2e -m "Release candidate baseline"Create a lightweight historical tag:
git tag test-baseline 7a93c2eVerify the target before tagging:
git show --no-patch --format=fuller 7a93c2eTagging the wrong commit can cause deployment and release confusion, especially after publication.
Inspect Tag References Precisely
Show the object referenced by the tag name:
git rev-parse v1.0.0For an annotated tag, this normally identifies the tag object itself.
Peel the tag to the commit it ultimately references:
git rev-parse v1.0.0^{}Require the referenced object to be a commit:
git rev-parse v1.0.0^{commit}Display the reference type:
git cat-file -t v1.0.0Typical results:
tagfor an annotated tag object.commitfor a lightweight tag pointing directly to a commit.
Show Tags Pointing at a Commit
List tags pointing directly to HEAD:
git tag --points-at HEADCheck another revision:
git tag --points-at 7a93c2eThis helps verify whether a release tag already exists at a selected commit.
List Tags Containing a Commit
Show tags whose referenced commits contain a selected commit in their history:
git tag --contains <commit>Show tags that do not contain it:
git tag --no-contains <commit>This can help answer:
Which releases include a security fix?
Was a bug introduced before or after a release?
Which release lines contain a selected commit?
Containment is based on commit ancestry, not whether identical code was introduced independently elsewhere.
Sort Tags
Lexicographic sorting can produce surprising results:
v1.10.0
v1.2.0
v1.9.0Use version-aware sorting:
git tag --sort=version:refnameReverse it:
git tag --sort=-version:refnameSort annotated tags by tagger date:
git tag --sort=-taggerdateLightweight tags do not have a dedicated tagger date, so date-based displays can require different fields depending on the tag type.
Format a custom tag list:
git for-each-ref \
--sort=-version:refname \
--format="%(refname:short) %(objecttype) %(subject)" \
refs/tagsSearch Tag Names
List stable version-one tags:
git tag -l "v1.*"List release candidates:
git tag -l "*-rc.*"Quote wildcard patterns so the shell does not expand them against filenames before Git receives the pattern.
Delete a Local Tag
git tag -d v0.1.0This removes the local tag reference.
It does not automatically remove a tag already published to a remote repository.
Before deleting:
git show v0.1.0
git rev-parse v0.1.0^{}Confirm that you are removing the intended reference.
Replace or Move a Local Tag
Tags are expected to remain stable, but during private local preparation you may need to correct one.
Delete and recreate it:
git tag -d v1.0.0
git tag -a v1.0.0 <correct-commit> -m "Release version 1.0.0"Or force replacement locally:
git tag -f -a v1.0.0 <correct-commit> -m "Release version 1.0.0"Force replacement changes what the name identifies. Do not do this casually after the tag has been shared.
Why Published Tags Should Be Treated as Immutable
Suppose a team publishes v1.0.0 pointing to commit A. Users, CI systems, deployment tools, and package builders may download or cache that tag.
If the tag is later moved to commit B, different people can hold different meanings for the same release name:
Developer 1: v1.0.0 -> A
Developer 2: v1.0.0 -> B
Build cache: v1.0.0 -> A
Deployment system: v1.0.0 -> BThis damages reproducibility and trust.
When a published release is wrong, the safer approach is usually to create a new version:
v1.0.1
v1.0.0-hotfix.1
v1.0.1-rc.1Use the versioning convention adopted by the project.
Signed Tags
An annotated tag can be cryptographically signed when signing keys and Git configuration are prepared.
Create a signed tag:
git tag -s v1.0.0 -m "Release version 1.0.0"Depending on the configured signing format and key setup, Git creates a signature in the tag object.
Verify a tag signature:
git tag -v v1.0.0Or:
git verify-tag v1.0.0Verification requires access to the appropriate public key or trust configuration.
A valid cryptographic signature confirms that the tag object was signed by the holder of the corresponding private key. It does not automatically prove that the software is secure, bug-free, or approved by your organization.
Signed Tag vs Signed Commit
A signed tag signs the tag object. A signed commit signs an individual commit object.
They can be used independently:
A signed release tag may point to unsigned commits.
A signed commit may have an unsigned tag.
A project may require both.
A project may rely on hosting-platform release attestations or another verification system.
Use the release trust policy defined by the project rather than assuming one signature covers every artifact and process.
Create a Practical Release Tag
Before tagging a release:
Confirm the correct branch.
Ensure the working tree is clean.
Fetch or synchronize remote state according to team policy.
Run tests and build checks.
Review the commit that will be tagged.
Confirm the version number.
Create the annotated or signed tag.
Inspect the tag before publishing it.
Example:
git switch main
git status
git log -1 --format=fuller
git diff HEAD^ HEAD
git tag -a v1.0.0 -m "Release Task Notes 1.0.0"
git show v1.0.0The tag should identify an exact tested commit, not an uncommitted working directory.
Push One Tag to a Remote
Normal branch pushes do not necessarily publish every local tag.
Push one tag explicitly:
git push origin v1.0.0This is the safest common release behavior because it publishes the exact intended tag.
Push All Local Tags
git push origin --tagsThis pushes all local tags missing from the remote.
Use it carefully. A developer may have temporary, private, experimental, or obsolete local tags that should not be published.
Before running it:
git tag --list
git for-each-ref --format="%(refname:short) %(objecttype) %(subject)" refs/tagsPush Reachable Annotated Tags with --follow-tags
When pushing branches, use:
git push --follow-tagsThis can push annotated tags that are missing from the remote and reachable from the commits being pushed.
It does not behave exactly like --tags and does not publish every local lightweight tag.
This makes it useful for release workflows that use annotated tags and want to avoid publishing unrelated local labels.
Delete a Remote Tag
Delete through an explicit remote ref operation:
git push origin --delete v1.0.0Another explicit form is:
git push origin :refs/tags/v1.0.0Deleting a remote tag does not automatically delete copies already fetched by other users.
If a published tag must be replaced, communicate clearly, use explicit refspecs, and understand that clients may retain the old tag until they deliberately update or delete it.
Fetch Tags
Normal fetch operations often obtain tags that point into fetched history according to Git’s tag-following behavior.
Fetch tags explicitly:
git fetch --tagsFetch one tag through an explicit refspec:
git fetch origin tag v1.0.0Inspect after fetching:
git tag --list
git show v1.0.0Do not assume a tag is trustworthy merely because it exists on a remote. Verify its target, metadata, and signature according to the project’s security model.
Check Out a Tag
Inspect a tagged version in detached-HEAD mode:
git switch --detach v1.0.0This is useful for:
Building an old release.
Running historical tests.
Inspecting a production version.
Comparing behavior across releases.
Do not create ongoing work in detached mode unless you plan to preserve it.
Create a maintenance branch from the tag:
git switch -c support/1.0 v1.0.0Now new commits move the maintenance branch while the tag remains fixed.
Compare Releases
List commits introduced between releases:
git log --oneline v1.0.0..v1.1.0Compare content:
git diff v1.0.0 v1.1.0Show summary statistics:
git diff --stat v1.0.0 v1.1.0Show changed paths:
git diff --name-status v1.0.0 v1.1.0These commands are useful for release notes, regression investigation, and deployment review.
Describe a Commit Relative to Tags
git describe creates a human-readable name based on a nearby reachable tag:
git describeExample:
v1.0.0-5-g7a93c2eThis commonly means:
The nearest considered tag is
v1.0.0.The commit is five commits after that tag.
The abbreviated object identifier begins with
7a93c2e.
Include lightweight tags:
git describe --tagsAlways include a fallback object identifier even when no suitable tag is found:
git describe --tags --alwaysThis can be useful for development build identifiers.
Tag Naming Conventions
Common release names include:
v1.0.0
v1.2.3
v2.0.0-rc.1
release-2026.07
production-2026-07-10A useful convention should be:
Consistent.
Documented.
Sortable or parseable by release tools.
Compatible with package and deployment systems.
Stable after publication.
Do not mix several unrelated schemes without a clear reason.
Semantic Versioning at a High Level
Many projects use a version structure such as:
MAJOR.MINOR.PATCHFor example:
2.4.1A typical interpretation is:
MAJOR: Incompatible public changes.
MINOR: Backward-compatible functionality.
PATCH: Backward-compatible fixes.
Prerelease identifiers can represent candidates:
2.5.0-alpha.1
2.5.0-beta.1
2.5.0-rc.1Git does not enforce Semantic Versioning. The tag name is only a reference name. Version meaning must be defined by the project and its release policy.
Tag Objects Can Point to More Than Commits
A Git tag reference can identify an object of another type, although release tags normally point to commits.
Annotated tag objects can point to commits, trees, blobs, or other tag objects.
Most developer workflows should tag commits because a commit identifies a complete project snapshot and history context.
Release Tags and Hosting-Platform Releases
A Git tag and a hosting-platform release are related but not identical.
The Git tag is a repository reference. A platform release may add:
Release notes.
Downloadable archives.
Compiled binaries.
Assets.
Approval workflows.
Deployment integration.
Provenance or attestation information.
The release interface usually uses a Git tag as its source version, but the surrounding metadata belongs to the hosting platform.
Practical Workflow: Pause a Feature for an Urgent Fix
1. Inspect Unfinished Work
git status
git diff
git diff --staged2. Stash It with Untracked Files
git stash push -u -m "WIP: task search filtering"3. Confirm a Clean State
git status
git stash list4. Switch to the Fix Branch
git switch main
git switch -c hotfix/task-import5. Implement and Commit the Fix
git add -p
git commit -m "Reject malformed imported task dates"6. Return to the Feature
git switch feature/search7. Inspect and Apply the Stash
git stash show -p stash@{0}
git stash apply stash@{0}8. Verify Before Dropping
git status
# Run tests and inspect files
git stash drop stash@{0}Using apply followed by a deliberate drop gives you a verification step.
Practical Workflow: Turn Old Stashed Work into a Branch
Inspect the stash:
git stash list
git stash show -p stash@{2}Create a branch from its original base:
git stash branch feature/recovered-search stash@{2}Then:
git status
git diff
git diff --stagedOrganize the recovered changes into meaningful commits.
Practical Workflow: Create and Publish a Release Tag
1. Verify the Release Commit
git switch main
git status
git log -1 --format=fuller
git show --stat HEAD2. Run Release Checks
# Examples only; use the project’s real commands
php vendor/bin/phpunit
npm run build3. Create an Annotated Tag
git tag -a v1.0.0 -m "Release Task Notes 1.0.0"4. Inspect the Tag
git show v1.0.0
git rev-parse v1.0.0^{commit}5. Publish Only the Intended Tag
git push origin v1.0.06. Verify Remote Release Automation
Confirm that CI, package creation, deployment, and release-note workflows completed successfully.
Common Stash Mistakes
Assuming Untracked Files Are Included Automatically
Use -u when untracked files belong in the stash.
Using --all Without Inspecting Ignored Content
Ignored dependency and build directories can make the stash unexpectedly large.
Using pop Before Inspecting an Old Stash
Use stash show and consider apply first.
Leaving Important Work in Stash for Months
Convert important work into a branch with commits.
Dropping the Wrong Stash Number
Stash positions can change after deletion. Run git stash list immediately before dropping.
Expecting --index Always to Restore Perfectly
The current repository state may prevent the old index arrangement from applying cleanly.
Assuming a Stash Is Shared with the Remote
Stashes normally remain local and are not published by normal branch pushes.
Using Stash to Hide a Disorganized Working Tree
Repeated stashing without messages or cleanup creates a second backlog that is difficult to understand.
Common Tag Mistakes
Confusing a Tag with a Branch
A tag normally remains fixed; a branch moves with development.
Tagging the Wrong Commit
Inspect the commit and test result before creating the release tag.
Using a Lightweight Tag for a Formal Release Without Intention
Annotated tags preserve release-specific metadata and messages.
Pushing All Tags Blindly
git push --tags may publish private or experimental local tags.
Moving a Published Version Tag
Different users and build systems may retain different targets for the same name.
Assuming a Signed Tag Proves Software Safety
A signature verifies the tag object and key relationship, not the correctness of the software.
Deleting a Remote Tag and Assuming It Disappears Everywhere
Other clones may retain the old local tag until they remove or replace it deliberately.
Creating Releases from an Unclean Working Tree
A tag identifies a committed object. Uncommitted local files are not included in that release reference.
Stash Command Reference
| Command | Purpose |
|---|---|
git stash push -m "message" | Stash tracked working and index changes with a message |
git stash push -u | Include untracked files |
git stash push -a | Include untracked and ignored files |
git stash push --keep-index | Keep staged changes in the index |
git stash push --staged | Stash staged changes |
git stash push -p | Select hunks interactively |
git stash push -- path | Stash selected paths |
git stash list | List stash entries |
git stash show -p | Inspect the latest stash patch |
git stash apply | Restore changes and keep the stash |
git stash apply --index | Attempt to restore changes and staged state |
git stash pop | Restore changes and drop after success |
git stash branch name stash@{n} | Create a branch from the stash’s original base and apply it |
git stash drop stash@{n} | Remove one stash entry |
git stash clear | Remove all stash entries |
Tag Command Reference
| Command | Purpose |
|---|---|
git tag | List local tags |
git tag v1.0.0 | Create a lightweight tag |
git tag -a v1.0.0 -m "message" | Create an annotated tag |
git tag -s v1.0.0 -m "message" | Create a signed annotated tag |
git tag -a v1.0.0 commit | Tag a selected historical commit |
git show v1.0.0 | Inspect a tag and referenced object |
git tag --points-at HEAD | List tags pointing at a revision |
git tag --contains commit | List tags whose histories contain a commit |
git tag --sort=version:refname | Sort names using version-aware ordering |
git tag -d v1.0.0 | Delete a local tag |
git tag -v v1.0.0 | Verify a signed tag |
git push origin v1.0.0 | Publish one tag |
git push origin --tags | Publish all local tags |
git push --follow-tags | Push suitable reachable annotated tags with branch updates |
git push origin --delete v1.0.0 | Delete a tag from a remote |
git switch --detach v1.0.0 | Inspect a tagged version |
git switch -c support/1.0 v1.0.0 | Create a branch from a tag |
Stash Checklist
Before creating a stash:
Run
git status.Decide whether untracked or ignored files are required.
Review staged and unstaged changes.
Use a descriptive message.
Consider whether a branch and commit would be safer.
Before applying or dropping a stash:
Run
git stash list.Inspect the selected patch.
Check the current branch and working tree.
Prefer
applywhen verification is needed.Run tests after restoration.
Drop only after confirming the work is preserved elsewhere.
Release Tag Checklist
The intended release commit is checked and tested.
The working tree is clean.
The version name follows project conventions.
The tag type is appropriate for the release policy.
The annotation explains the release.
The tag points to the correct commit.
Required signing and verification steps are complete.
Only the intended tag is published.
Release artifacts are built from the tagged commit.
The published tag will not be moved casually.
Frequently Asked Questions
Does Git Stash Save Untracked Files?
Not by default. Use git stash push -u to include untracked files.
Does -u Include Ignored Files?
No. Use -a or --all when ignored files must also be included.
What Is the Difference Between Apply and Pop?
Both restore stashed changes. apply keeps the stash entry; pop removes it after a successful application.
Can I Apply a Stash to a Different Branch?
Yes, but conflicts are more likely when the target branch differs significantly from the stash’s original base.
Can I Share a Stash?
Normal stash entries are local. For collaboration, create a branch and commit the work, or use a deliberate advanced transfer workflow.
Is Stash Safe for Long-Term Work?
It is designed primarily for temporary local work. Important long-term changes should be preserved through branches, commits, and remote copies.
What Is the Difference Between a Lightweight and Annotated Tag?
A lightweight tag is a direct reference. An annotated tag creates a tag object with tagger metadata, date, message, and optional signature.
Should Releases Use Annotated Tags?
Annotated or signed tags are generally better suited to formal releases because they store explicit release metadata.
Does git push Publish Tags Automatically?
Not every local tag is necessarily pushed by a normal branch push. Publish the intended tag explicitly or use a carefully selected tag-push option.
Can I Change a Tag?
You can replace a local tag, but changing a published tag can create inconsistent release identities across clones and systems.
Can a Tag Point to a Branch?
A tag resolves to an object, not to a branch’s future movement. Creating a tag from a branch name tags the object currently referenced by that branch.
Can I Commit While Checked Out at a Tag?
You can create commits in detached-HEAD mode, but no branch moves automatically. Create a branch first when the work must be preserved clearly.
Does a Signed Tag Mean the Release Binary Is Signed?
No. It signs the Git tag object. Release binaries, containers, packages, and attestations may require separate signing and verification.
Conclusion
Git stash and tags operate at opposite ends of a development workflow.
Stash manages unfinished local work. It lets you temporarily clean the working tree, preserve selected tracked or untracked changes, move work to another branch, and return later. Its power comes with a responsibility: inspect what is being stored, use descriptive messages, restore cautiously, and convert important long-lived work into normal commits.
Tags identify stable historical points. Lightweight tags provide simple labels, while annotated and signed tags carry stronger release metadata. A well-managed tag points to a tested commit, follows a consistent versioning scheme, and remains stable after publication.
The most important distinction is durability and intent. A stash is a temporary private work container. A release tag is a shared promise that a specific name identifies a specific project state.
The next article will examine Git workflows, including feature branches, GitHub Flow, Git Flow, trunk-based development, release branches, hotfix strategies, and how to select a workflow that matches the size and delivery model of a team.
Official References and Further Reading

