GitChecking Out a Tag

Checking Out a Tag

Checking out a tag lets you inspect the exact state of the codebase at a historical release point. However, unlike checking out a branch, checking out a tag puts Git into a special state called detached HEAD. Understanding this state — and knowing when to create a branch from the tag instead — is essential for working safely with tagged releases.

Checking out a tag puts you in detached HEAD

Check out a tag

Bash
git checkout v1.0.0
# Note: switching to 'v1.0.0'.
#
# You are in 'detached HEAD' state. You can look around, make experimental
# changes and commit them, and you can discard any commits you make in this
# state without impacting any branches by switching back to a branch.
#
# If you want to create a new branch to retain commits you make, you may
# do so (now or later) by using -c with the switch command. Example:
#
#   git switch -c <new-branch-name>
#
# Or undo this operation with:
#
#   git switch -
#
# HEAD is now at 3f8a2c9 Final tweaks before release
What detached HEAD means

In a normal state, HEAD points to a branch name, and that branch name points to a commit. When HEAD points directly to a commit SHA instead of a branch name, you are in detached HEAD state.

Normal state vs detached HEAD

Text
Normal state (HEAD → branch → commit):
─────────────────────────────────────────────────
  .git/HEAD contains:  ref: refs/heads/main

  HEAD ──▶ main ──▶ commit 9a8b7c6
                            │
  A───B───C  ◀── main (HEAD is here via the branch)

Detached HEAD state (HEAD → commit directly):
─────────────────────────────────────────────────
  .git/HEAD contains:  3f8a2c9d...  (raw SHA)

  A───B───C───D  ◀── main
          │
  HEAD ──▶ C (3f8a2c9, tagged v1.0.0)
          tag: v1.0.0

New commits made in this state are NOT on any branch:
  A───B───C───D  ◀── main
          │
          C (v1.0.0, HEAD) ──▶ E (new commit, orphaned)
          (E has no branch pointing to it — will be GC'd)
Commits made in detached HEAD state can be lost
If you make commits while in detached HEAD state and then switch to a branch without first creating a branch for those commits, Git will eventually garbage-collect them. They are not permanently safe until a branch or tag points to them.
Modern syntax: git switch for tags

Use git switch --detach for clarity

Bash
# Modern, explicit way to enter detached HEAD at a tag
git switch --detach v1.0.0
# HEAD is now at 3f8a2c9 Final tweaks before release

# Check what you are on
git status
# HEAD detached at v1.0.0
# nothing to commit, working tree clean

# Or use the older git checkout syntax (still valid):
git checkout v1.0.0
Exploring code in detached HEAD (read-only usage)

The most common reason to check out a tag is to read and explore the codebase at a past release — inspecting files, running the old version, reproducing a bug. For read-only exploration, detached HEAD is perfectly fine.

Safe read-only exploration of a tagged release

Bash
# Check out the tag
git checkout v1.0.0
# HEAD is now at 3f8a2c9 Final tweaks before release

# Explore the files — everything looks like it did at v1.0.0
ls src/
# (files as they existed at v1.0.0)

cat package.json | grep '"version"'
# "version": "1.0.0"

# Run the old version
npm install && npm start

# When done, return to your branch
git switch main
# Switched to branch 'main'
# Your branch is up to date with 'origin/main'.
Creating a branch from a tag to make changes

If you need to make changes based on a tagged release — for example, applying a hotfix to an older version — you must create a branch from the tag. This gives your new commits a permanent home.

Create a branch from a tag and commit to it

Bash
# Option 1: checkout the tag, then create a branch
git checkout v1.0.0
git switch -c hotfix-1.0.1
# Switched to a new branch 'hotfix-1.0.1'

# Option 2 (direct, no intermediate checkout needed):
git switch -c hotfix-1.0.1 v1.0.0
# Switched to a new branch 'hotfix-1.0.1'

# Now you are on a real branch — commits are safe
git status
# On branch hotfix-1.0.1
# nothing to commit, working tree clean

# Make your fix
git add .
git commit -m "Fix critical null-pointer exception in payment handler"

# Tag the hotfix release
git tag -a v1.0.1 -m "Hotfix release 1.0.1"

# Push the branch and tag
git push -u origin hotfix-1.0.1
git push origin v1.0.1
Using git switch -c vs git checkout -b

Command

Modern/Legacy

Notes

git switch -c hotfix v1.0.0

Modern (Git 2.23+)

Preferred — clear intent, explicit

git checkout -b hotfix v1.0.0

Classic (all Git versions)

Still widely used, works identically

git checkout v1.0.0 then git switch -c hotfix

Two steps

Works but less efficient than one-step

Confirm which tag you are on

Verify your current position in history

Bash
# Check HEAD position
git status
# HEAD detached at v1.0.0
# nothing to commit, working tree clean

# Describe the current commit relative to tags
git describe --tags HEAD
# v1.0.0   (exactly on the tag)

git describe --tags HEAD
# v1.0.0-3-gabc1234   (3 commits after v1.0.0, not on the tag itself)

# Show all tags pointing to the current commit
git tag --points-at HEAD
# v1.0.0

# Show the full commit info
git log -1 HEAD
# commit 3f8a2c9d...
# (tag: v1.0.0)
Return to a branch after exploring a tag

Exit detached HEAD and return to a branch

Bash
# Return to main (or whichever branch you were on)
git switch main
# Switched to branch 'main'

# Or using the classic syntax
git checkout main

# If you are not sure which branch to return to:
git branch
# * (HEAD detached at v1.0.0)
#   feature-auth
#   hotfix-1.0.1
#   main

git switch main
Common errors

Error: tag not found

Bash
git checkout v9.9.9
# error: pathspec 'v9.9.9' did not match any file(s) known to git

# Fix: verify the tag exists
git tag | grep v9
# (nothing — the tag does not exist locally)

# Maybe it exists on the remote but was not fetched yet:
git fetch --tags
git checkout v9.9.9

Accidentally made commits in detached HEAD

Bash
# You made commits while detached — now you want to save them
git log --oneline -3
# e5f6a7b (HEAD) My important fix
# d4e5f6a Another change
# 3f8a2c9 (tag: v1.0.0) Final tweaks before release

# Save the commits by creating a branch before switching away
git switch -c my-fix-branch
# Switched to a new branch 'my-fix-branch'
# (commits are now safe on this branch)

# If you already switched away (commits are now dangling):
# Find them with reflog
git reflog
# abc1234 HEAD@{1}: commit: My important fix
# 3f8a2c9 HEAD@{3}: checkout: moving from main to v1.0.0

git switch -c my-fix-branch abc1234
git checkout vs git switch
`git switch` was introduced in Git 2.23 to give a clearer, less overloaded interface. `git switch --detach v1.0.0` is more explicit than `git checkout v1.0.0` because it clearly states you intend to enter detached HEAD. Both commands are valid — `git checkout` is not deprecated.
Build and test a release by checking out its tag
When investigating a regression, check out the last known-good release tag, build and test it, then compare with newer tags to identify which release introduced the regression. Combine with `git bisect` for even more efficiency.