Lesson 3: Branching — Parallel Universes
Understanding what branches really are, how to create and manage them, and why they're fundamental to Git workflows.
Lesson 3: Branching — Parallel Universes 🌳
Introduction
Imagine you're writing a novel. You have a complete first draft, but you want to experiment with a different ending. Instead of deleting chapters and rewriting (potentially losing your original), you make a photocopy of the entire manuscript and work on the copy. If the new ending works, great! If not, you still have the original. That's exactly what Git branches let you do with code—create parallel timelines where you can experiment without fear.
In this lesson, we'll demystify branches by understanding what they really are under the hood, master the essential commands, and learn why branches are one of Git's most powerful features. By the end, you'll see branches not as scary complexity but as lightweight, indispensable tools.
Core Concepts
What Branches Really Are 🔍
Here's the truth that changes everything: a branch is just a pointer to a commit. That's it. Not a copy of files, not a separate folder, just a 41-byte file containing a commit hash.
Let's visualize this:
Commit History:
C1 ← C2 ← C3 ← C4
↑
main (branch pointer)
HEAD (you are here)
In this diagram:
C1,C2,C3,C4are commits (snapshots of your project)mainis a branch pointer that points to commitC4HEADis a special pointer showing which branch you're currently on
When you create a new branch, Git simply creates another pointer:
C1 ← C2 ← C3 ← C4
↑
main
feature-login
HEAD
Both main and feature-login point to the same commit! No files were copied. This is why branches are incredibly cheap in Git—creating 100 branches uses less disk space than a single image file.
💡 Tip: Think of branches as bookmarks in a book, not photocopies of the book itself.
How Branches Move Forward ⏩
When you make a new commit, only the branch that HEAD points to moves forward:
Before commit:
C1 ← C2 ← C3 ← C4
↑
main
feature-login ← HEAD
After commit:
C1 ← C2 ← C3 ← C4 ← C5
↑ ↑
main feature-login ← HEAD
Notice that main stayed at C4 while feature-login moved to C5. This is the parallel universe concept—each branch can evolve independently.
The HEAD Pointer 🎯
HEAD is Git's way of tracking "where you are right now." It almost always points to a branch (which points to a commit). When you switch branches, you're just moving HEAD:
# Switching to main:
C1 ← C2 ← C3 ← C4 ← C5
↑ ↑
HEAD → main feature-login
Your working directory instantly updates to match commit C4—the files literally change on disk to reflect that snapshot.
⚠️ Important: HEAD is what makes commands like git commit know which branch to update.
Branch Naming Conventions 📝
While Git allows almost any branch name, following conventions makes collaboration easier:
+------------------------+----------------------------------+
| Convention | Example |
+------------------------+----------------------------------+
| Feature branches | feature/user-authentication |
| | feature/add-payment-gateway |
+------------------------+----------------------------------+
| Bug fix branches | bugfix/fix-login-timeout |
| | hotfix/critical-security-patch |
+------------------------+----------------------------------+
| Experimental branches | experiment/new-algorithm |
| | spike/performance-test |
+------------------------+----------------------------------+
| Release branches | release/v2.1.0 |
| | release/2024-q1 |
+------------------------+----------------------------------+
Common patterns:
- Use lowercase with hyphens:
feature/user-profile✅ notFeature_UserProfile❌ - Be descriptive:
fix-payment-bug✅ notfix❌ - Use prefixes to categorize:
feature/,bugfix/,docs/
🧠 Mnemonic: F.B.E.R. - Features, Bugs, Experiments, Releases—four main branch categories.
Essential Branch Commands 💻
Creating Branches
Command: git branch <branch-name>
This creates a new branch pointer at your current commit but doesn't switch to it:
$ git branch feature-dashboard
# Creates branch, but you're still on main
C1 ← C2 ← C3 ← C4
↑
HEAD → main
feature-dashboard
💡 Tip: Think of git branch as "create a bookmark" not "open to that page."
Switching Branches
Command: git checkout <branch-name> or git switch <branch-name> (newer, clearer)
$ git switch feature-dashboard
Switched to branch 'feature-dashboard'
C1 ← C2 ← C3 ← C4
↑
main
HEAD → feature-dashboard
Your working directory now reflects commit C4 through the lens of feature-dashboard.
Create and Switch in One Command ⚡
Command: git checkout -b <branch-name> or git switch -c <branch-name>
This is the most common pattern—create and immediately switch:
$ git switch -c feature-notifications
Switched to a new branch 'feature-notifications'
🔧 Try this: Create a branch called experiment and switch to it with one command.
Listing Branches
Command: git branch (no arguments)
$ git branch
experiment
feature-dashboard
* main
release/v1.0
The * shows your current branch (where HEAD points). Use git branch -v for more details:
$ git branch -v
experiment 7a3f2e1 Add experimental feature
feature-dashboard 9b4c8d2 Update dashboard layout
* main 4f6e7a3 Fix typo in README
release/v1.0 2d5c9f8 Prepare v1.0 release
Deleting Branches
Command: git branch -d <branch-name> (safe delete) or git branch -D <branch-name> (force delete)
$ git branch -d feature-dashboard
Deleted branch feature-dashboard (was 9b4c8d2).
Git will prevent deletion with -d if the branch has unmerged work:
$ git branch -d experiment
error: The branch 'experiment' is not fully merged.
If you are sure you want to delete it, run 'git branch -D experiment'.
⚠️ Safety feature: The lowercase -d protects you from losing work. Use -D only when you're certain.
Practical Examples 🛠️
Example 1: Feature Branch Workflow
Let's walk through developing a new login feature:
# Start on main branch
$ git switch main
# Create and switch to feature branch
$ git switch -c feature/login-page
# Make changes to login.html
$ echo "<form>Login form</form>" > login.html
$ git add login.html
$ git commit -m "Add basic login form"
# Continue working
$ echo "<input type='password'>" >> login.html
$ git add login.html
$ git commit -m "Add password field to login"
# Check your branch history
$ git log --oneline
ab3f2e1 (HEAD -> feature/login-page) Add password field to login
9c7d4a2 Add basic login form
4f6e7a3 (main) Fix typo in README
Visualized:
main: C1 ← C2 ← C3
↑
main
feature/login-page: C1 ← C2 ← C3 ← C4 ← C5
↑
feature/login-page ← HEAD
Example 2: Switching Between Contexts
You're working on a feature when an urgent bug is reported:
# Currently on feature branch
$ git switch feature/new-api
# ... working on API changes ...
# Urgent bug reported! Need to fix on main
$ git switch main
# Create hotfix branch
$ git switch -c hotfix/critical-security
# Fix the bug
$ echo "Security patch applied" > security.txt
$ git add security.txt
$ git commit -m "HOTFIX: Patch security vulnerability"
# Deploy this fix, then return to feature work
$ git switch feature/new-api
# ... continue where you left off ...
💡 The power of branches: You can context-switch instantly without losing any work. Each branch maintains its own timeline.
Example 3: Viewing Branch Structure
Use git log --all --graph --oneline to visualize branch relationships:
$ git log --all --graph --oneline
* ab3f2e1 (feature/login-page) Add password field
* 9c7d4a2 Add basic login form
| * 2d8c3a1 (hotfix/critical-security) HOTFIX: Security patch
|/
* 4f6e7a3 (HEAD -> main) Fix typo in README
* 3a2b1c4 Initial commit
This ASCII art shows the parallel development clearly.
Example 4: Checking Branch Status Before Deletion
Always verify a branch's status before deleting:
# See which branches are merged into main
$ git branch --merged main
feature/completed-feature
* main
old-experiment
# Safe to delete these (they're already in main)
$ git branch -d feature/completed-feature
Deleted branch feature/completed-feature (was 8a3c9d1).
# See which branches are NOT merged
$ git branch --no-merged main
feature/in-progress
feature/login-page
# These have unique commits - be careful deleting!
Why Branches Are Cheap 💰
Let's look at what actually happens on disk:
.git/refs/heads/
├── main (41 bytes - just a commit hash)
├── feature-login (41 bytes)
└── hotfix-security (41 bytes)
Each branch is literally just a file containing a commit SHA-1 hash. Creating 1,000 branches uses about 41 KB—less than a single icon file!
Comparison with other version control systems:
+------------------+------------------------+-------------------+
| System | Branch Operation | Cost |
+------------------+------------------------+-------------------+
| Git | Create pointer | ~41 bytes |
| Subversion (SVN) | Copy entire directory | Full repo size |
| Perforce | Create branch spec | Moderate |
+------------------+------------------------+-------------------+
🤔 Did you know? Some Git repositories have thousands of branches. The Linux kernel repository has over 200 active branches at any given time!
This cheapness means:
- ✅ Create a branch for every feature, no matter how small
- ✅ Experiment freely—branches cost nothing
- ✅ Keep multiple contexts active simultaneously
- ✅ Delete branches liberally after merging
Common Branch Workflows 🔄
The Feature Branch Pattern
1. Start: main is stable
main: C1 ← C2 ← C3
2. Create feature branch
git switch -c feature/new-ui
3. Develop feature (multiple commits)
feature/new-ui: C1 ← C2 ← C3 ← C4 ← C5 ← C6
4. Merge back to main (we'll cover this in Lesson 4)
5. Delete feature branch
git branch -d feature/new-ui
Short-Lived vs. Long-Lived Branches
Short-lived (typical feature branches):
- Created for a single feature or bug fix
- Merged within days or weeks
- Deleted after merge
- Examples:
feature/add-comments,bugfix/fix-typo
Long-lived (persistent branches):
- Exist throughout project lifetime
- Represent deployment environments or major versions
- Never deleted
- Examples:
main,develop,production,release/v2.x
Common Mistakes ⚠️
Mistake 1: Forgetting Which Branch You're On
# Thinking you're on feature branch, but...
$ git branch
feature/new-api
* main # ← You're actually here!
$ git commit -m "Add API endpoint" # ❌ Commits to main by accident!
Prevention: Always check your branch before committing. Many developers configure their shell prompt to display the current branch:
user@computer (main) $ git switch feature/new-api
user@computer (feature/new-api) $ # ✅ Clear visual indicator
Mistake 2: Creating a Branch from the Wrong Starting Point
# You're on feature-A
$ git branch
* feature-A
main
# Create feature-B (it branches from feature-A, not main!)
$ git switch -c feature-B # ❌ Wrong parent branch
Prevention: Always switch to the correct base branch first:
$ git switch main # ✅ Go to the right starting point
$ git switch -c feature-B # ✅ Now branches from main
Mistake 3: Leaving Uncommitted Changes When Switching
$ git status
Modified: index.html # Uncommitted changes
$ git switch other-branch
error: Your local changes to the following files would be overwritten:
index.html
Please commit your changes or stash them before you switch branches.
Solution: Commit or stash your changes:
# Option 1: Commit them
$ git add index.html
$ git commit -m "WIP: Partial work on homepage"
# Option 2: Stash them (we'll cover this more in Lesson 5)
$ git stash
$ git switch other-branch
Mistake 4: Deleting Branches with Unmerged Work
$ git branch -d feature/important
error: The branch 'feature/important' is not fully merged.
This is Git protecting you! If you force delete with -D, those commits may become unreachable and eventually be garbage collected.
Check first:
# See what's in the branch
$ git log main..feature/important
# If you're SURE you want to delete:
$ git branch -D feature/important # Only if you're certain!
Mistake 5: Using Spaces or Special Characters in Branch Names
$ git switch -c "my feature branch" # ❌ Spaces cause issues
$ git switch -c my@feature # ❌ @ can cause problems
Best practice: Use lowercase, hyphens, and forward slashes only:
$ git switch -c my-feature-branch # ✅
$ git switch -c feature/my-new-feature # ✅
Key Takeaways 🎯
Branches are just pointers to commits—they're not copies of your files. This makes them incredibly lightweight and fast.
HEAD points to your current branch, which points to a commit. Moving HEAD is what "switching branches" means.
Creating branches is cheap—each branch is just 41 bytes. Never hesitate to create a branch for any experiment or feature.
Use descriptive naming conventions:
feature/,bugfix/,hotfix/prefixes help organize branches.Always know which branch you're on before committing. Check with
git branchor configure your terminal prompt.Start branches from the right parent—switch to your base branch (usually
main) before creating a new branch.Safe deletion with
-dprevents losing unmerged work. Use-Donly when you're absolutely certain.Branches enable parallel development—work on multiple features simultaneously without interference.
📚 Further Study
Git Branching - Branches in a Nutshell: https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell
The official Git documentation's deep dive into how branches work internally.Git Branch Documentation: https://git-scm.com/docs/git-branch
Complete reference for allgit branchcommand options.Atlassian Git Branch Tutorial: https://www.atlassian.com/git/tutorials/using-branches
Practical guide with visual diagrams and real-world workflows.
📋 Quick Reference Card
+--------------------------------+----------------------------------------+
| Command | Purpose |
+--------------------------------+----------------------------------------+
| git branch | List all local branches |
| git branch <name> | Create new branch (don't switch) |
| git branch -d <name> | Delete branch (safe) |
| git branch -D <name> | Force delete branch |
| git branch -v | List branches with last commit |
| git branch --merged | Show branches merged into current |
| git branch --no-merged | Show branches not yet merged |
+--------------------------------+----------------------------------------+
| git switch <name> | Switch to branch (modern) |
| git switch -c <name> | Create and switch to branch |
| git checkout <name> | Switch to branch (traditional) |
| git checkout -b <name> | Create and switch (traditional) |
+--------------------------------+----------------------------------------+
| git log --all --graph --oneline| Visualize all branches |
+--------------------------------+----------------------------------------+
KEY CONCEPTS:
• Branch = pointer to a commit (just 41 bytes!)
• HEAD = pointer to current branch
• Switching branches = moving HEAD
• Creating branches is free—use them liberally
• Always check which branch you're on before committing
🧠 Remember: Branches are bookmarks, not photocopies. They point to commits in your Git history, making them essentially free to create and manipulate. This is what enables Git's powerful parallel development workflows!