Tags Are Database Snapshots You Can Name
Branches move. Every time you commit to a branch, it advances. That’s the point — branches are living, growing things.
But sometimes you need to mark an exact point in time and know it will never change. Before a risky migration. After a successful deployment. At the moment you ship version 2.0.
In SQL Server, you’d create a database snapshot. In git, you create a tag.

A Tag Is CREATE DATABASE SNAPSHOT
|
1 2 3 4 5 |
CREATE DATABASE SNAPSHOT [AdventureWorks_BeforeMigration] AS ( NAME = N'AdventureWorks_Data', FILENAME = N'C:\Snapshots\AW_BeforeMigration.ss' ); |
That snapshot captures the database at that exact moment. No matter what happens next — schema changes, data modifications, disasters — you can always go back to that snapshot.
A git tag does the same thing:
|
1 |
git tag -a v2.0.0 -m "Production release 2.0.0 - before AG migration" |
That tag is permanently attached to the current commit. The branch will keep moving forward, but the tag stays right where you put it. It’s a photograph, not a living thing.
Lightweight vs. Annotated Tags
Git has two types of tags:
Lightweight tags are just a name pointing to a commit. No metadata, no message.
|
1 |
git tag v1.0.0 |
Annotated tags include who created the tag, when, and why. They’re stored as full objects in the git database.
|
1 |
git tag -a v2.0.0 -m "Production release - includes new backup framework" |
Always use annotated tags for anything important. The metadata matters when you’re looking back six months later trying to figure out what version was running when that incident happened.
It’s the difference between a snapshot with a description and a snapshot with just a timestamp.
Listing and Inspecting Tags
|
1 2 3 4 5 6 7 8 |
# List all tags git tag -l # List tags matching a pattern git tag -l "v2.*" # See details of a specific tag git show v2.0.0 |
|
1 2 3 4 5 6 7 8 9 10 11 |
tag v2.0.0 Tagger: Hannah Vernon <hannah@example.com> Date: Tue May 6 14:30:00 2026 -0500 Production release - includes new backup framework commit f4e5d6c... Author: Hannah Vernon <hannah@example.com> Date: Tue May 6 14:15:00 2026 -0500 Add backup automation framework with error handling |
That’s your audit trail. Who tagged it, when, why, and exactly which commit it points to.
Using Tags as Rollback Points
Here’s the DBA-critical use case. Before you do anything risky:
|
1 2 3 4 5 6 7 8 |
# Tag the current state git tag -a pre-migration -m "Safety snapshot before schema migration" # Do the scary work # ... make changes, commit them ... # Something went wrong? Check out the tag git switch --detach pre-migration |
You’re now looking at the exact state of your code before the migration. You can create a new branch from here, or just inspect what things looked like.
|
1 2 |
# Create a branch from the tagged point to work from git switch -c rollback-branch pre-migration |
This is RESTORE DATABASE FROM SNAPSHOT — go back to the known-good state and work from there.
Semantic Versioning
Most teams use tags for release versioning. The convention is semantic versioning:
|
1 2 3 |
v1.0.0 — major release (breaking changes) v1.1.0 — minor release (new features, backward-compatible) v1.1.1 — patch release (bug fixes only) |
For database projects, you might version your schema:
|
1 2 3 |
git tag -a v3.0.0 -m "Schema v3: added temporal tables, removed legacy views" git tag -a v3.1.0 -m "Schema v3.1: new reporting indexes" git tag -a v3.1.1 -m "Schema v3.1.1: fixed missing foreign key on Orders" |
Each tag is a permanent record of exactly what the schema looked like at that version.
Pushing Tags to the Remote
Tags are local by default. To share them with your team:
|
1 2 3 4 5 |
# Push a specific tag git push origin v2.0.0 # Push all tags at once git push origin --tags |
Until you push a tag, it only exists on your machine — just like a database snapshot only exists on the server where you created it.
Tags vs. Branches: The Key Difference
This is worth stating clearly because it trips people up:
A branch moves. Every new commit advances the branch pointer. It’s a living, growing thing — like a database that’s actively being modified.
A tag stays. It permanently marks one specific commit. It’s a snapshot — frozen in time.
Use branches for ongoing work. Use tags for milestones, releases, and safety checkpoints.
Try This Yourself
|
1 2 3 4 5 6 7 8 9 10 11 12 |
# Tag your current state git tag -a v-before-scary-change -m "Safety snapshot" # Make some changes echo "risky stuff" > danger.sql git add . && git commit -m "Risky change" # Oh no, go back git switch --detach v-before-scary-change # Verify — your risky change is gone ls |
The One Sentence to Remember
A tag is CREATE DATABASE SNAPSHOT — a permanent, named bookmark you can always return to, no matter how far the branch moves after it.
Previously: Rebase Is ALTER TABLE on Your Commit History
Next up: Cherry-Pick Is Cross-Database INSERT…SELECT