:bulb: Both branches and tags in Git are pointers to commits, but their purposes and behaviors differ. This post organizes the differences and practical usage of each.

[01] The Core Difference: Moving Pointer vs Fixed Pointer

1
2
3
4
5
          branch (moves)
              ↓
  A ← B ← C ← D ← E     ← when a new commit is added, branch follows
              ↑
          tag v1.0 (fixed)   ← tag always points to C
Aspect Branch Tag
Essence Moving pointer Fixed pointer
When a commit is added Automatically follows the latest commit Stays pinned to the commit at creation time
Purpose Development flow (branching work) Recording a specific moment (release, milestone)
Lifetime Typically deleted after merge Kept permanently
Analogy Sticky note (can be moved) Stamp (fixed once applied)

[02] Branch — Separating Development Flows

2-1. Concept

A branch is a tool for separating work. You can develop features, fix bugs, and experiment without affecting the main code.

1
2
3
4
5
6
7
8
9
10
11
12
13
# Create and switch to a branch
git checkout -b feature/login

# Work and commit
git add .
git commit -m "implement login feature"

# Merge into main
git checkout main
git merge feature/login

# Delete after the merge completes
git branch -d feature/login

2-2. When to Use Branches

Situation Example branch name
New feature development feature/login, feature/search
Bug fix fix/login-error, hotfix/payment
Experiment / prototype experiment/new-ui, spike/redis
Release preparation release/1.2.0
Environment separation develop, staging

2-3. Listing Branches

1
2
3
4
5
6
7
8
# Local branches
git branch

# All branches including remote
git branch -a

# Only merged branches (candidates for deletion)
git branch --merged

[03] Tag — Recording a Specific Moment

3-1. Concept

A tag is a tool that pins a specific commit with a name. Use it for release versions, deployment points, milestones — anytime you want to say “remember this point”.

1
2
3
4
5
# Create a tag (on the current commit)
git tag v1.0.0

# Push the tag to the remote
git push origin v1.0.0

3-2. Lightweight Tag vs Annotated Tag

Git has two kinds of tags.

(A) Lightweight Tag — a simple pointer

1
git tag v1.0.0

Creates only a pointer to a commit. It has no metadata such as author, date, or message.

1
git tag -a v1.0.0 -m "first official release"
Included info Example
Tag name v1.0.0
Author user <user@email.com>
Creation date 2026-03-26
Message first official release

:bulb: Annotated tags are recommended. They record who tagged this moment, when, and why. GitHub Releases also operates on annotated tags.

3-3. When to Use Tags

Situation Example tag name
Official release v1.0.0, v2.1.3
Beta / RC release v1.0.0-beta.1, v1.0.0-rc.1
Deployment record deploy-2026-03-26
Milestone milestone-mvp, sprint-5-done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# List tags
git tag

# Filter by pattern
git tag -l "v1.*"

# Show tag details
git show v1.0.0

# Tag a past commit
git tag -a v0.9.0 -m "beta release" abc1234

# Push all tags to the remote
git push origin --tags

# Delete a tag (local)
git tag -d v1.0.0

# Delete a tag (remote)
git push origin --delete v1.0.0

# Check out the state of a specific tag
git checkout v1.0.0

:warning: Checking out a tag puts you in detached HEAD state. Commits made in this state belong to no branch, so create a branch if you need to do work.

1
2
3
# Create a hotfix branch from a tag point
git checkout v1.0.0
git checkout -b hotfix/v1.0.1

[04] Practical Comparison: Which to Use in the Same Situation?

Situation Branch Tag Recommended
Starting login feature development feature/login - Branch
v1.0.0 release shipped - v1.0.0 Tag
Critical bug found after release hotfix/payment - Branch
Hotfix released after critical fix - v1.0.1 Tag
Starting development for the next version release/1.1.0 - Branch
“Let me come back to this commit” - backup-before-refactor Tag
Forking code for an A/B test experiment/new-checkout - Branch

:bulb: The rule of thumb is simple:

  • Going to add commits going forward → Branch
  • Want to pin this moment for memory → Tag

[05] Practical Workflow Example

A typical development-release flow where branches and tags work together.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 1. Feature development (branch)
git checkout -b feature/search
# ... work ...
git commit -m "implement search feature"

# 2. Merge into main
git checkout main
git merge feature/search
git branch -d feature/search

# 3. Release tag (tag)
git tag -a v1.2.0 -m "add search feature"
git push origin main --tags

# 4. Bug found after deploy → hotfix (branch)
git checkout -b hotfix/search-crash
# ... fix ...
git commit -m "fix search crash"

# 5. Merge + patch tag (tag)
git checkout main
git merge hotfix/search-crash
git branch -d hotfix/search-crash
git tag -a v1.2.1 -m "fix search crash"
git push origin main --tags
1
2
3
4
5
6
main:  A ─ B ─ C ─ D(merge) ─ E ─ F(merge)
              │         ↑              ↑
              │      v1.2.0         v1.2.1
              │
feature/search: C1 ─ C2
                         hotfix: E1

[06] Semantic Versioning (Tag Naming)

It is standard to follow Semantic Versioning (SemVer) rules when naming tags.

1
2
3
4
5
v MAJOR . MINOR . PATCH
  │       │       │
  │       │       └─ bug fix (backward compatible)
  │       └───────── feature addition (backward compatible)
  └───────────────── breaking change
Change Version change Example
Typo fix, bug fix PATCH +1 v1.0.0v1.0.1
New feature (compatible) MINOR +1 v1.0.1v1.1.0
API change (breaking) MAJOR +1 v1.1.0v2.0.0

[07] Summary

Item Branch Tag
One-line summary Ongoing work flow Snapshot of a completed point
Pointer Moves automatically when commits are added Fixed
Created when Before work starts After release/deployment completes
Deletion Typically deleted after merge Don’t delete (kept permanently)
Main use Branching for feature, fix, release Version releases, milestones
Push to remote git push origin branch git push origin tag
1
2
Branch = "in progress" marker
Tag    = "completed" stamp