Git 3a 🧩 Understanding Branches
A branch is an independent line of development. It lets you work on a feature, a fix, or an experiment without touching the stable version of your code. In Git, branches are cheap — creating one is instant, and switching between them is fast. That’s why branching is at the center of almost every Git workflow.
Key point: A branch in Git is just a movable pointer to a commit. It’s not a copy of the codebase — it’s a label that says “the latest work on this line of development lives here.” Understanding that changes how you think about branches.
What are branches?
A branch is a separate workspace for your code. Imagine building a house — instead of having everyone work on the same foundation, branches let different people work on different parts at the same time.
Think of branches as parallel universes of your code. Each one evolves independently. You can make changes, test ideas, and experiment without worrying about breaking the main project.
Branches are the way teams work on multiple things at once without stepping on each other.
Why do we use branches?
Three reasons cover almost every use case.
Feature development without risk — when you add a new feature, you don’t want to break the working system. You create a branch, build the feature in isolation, and merge only when it’s ready and tested.
Bug fixes in isolation — critical bugs need fixes, but a rushed fix can introduce more problems. A dedicated branch lets you fix, test, and verify before it touches production.
Experimentation and testing — developers try new approaches and technologies. Branches let them explore without affecting stable code that other people depend on.
The pattern is the same in all three: isolate work, then merge when ready.
Why this matters: Branches turn “risky change” into “safe experiment.” You can throw a branch away, rewrite it, or merge it — all without affecting anyone else.
The main branch
Every repository has a main branch — the official version of the project. It represents what should be in production, what users are actually running, and what gets deployed to customers.
Historically the main branch was called master. Modern Git and most hosting platforms default to main. Both names mean the same thing — the primary line of development.
The main branch is typically very stable. It only receives updates when features have been thoroughly tested and approved — usually via a pull request and code review.
Why it’s stable: Everyone depends on the main branch. If it breaks, deployments fail. That’s why changes land there carefully, not casually.
Understanding HEAD
HEAD is a marker that always points to your current location in the project history. Git uses it to know where you are.
Think of HEAD as a spotlight — it always shines on the commit you’re currently on.
- When you’re on the main branch, HEAD points to the latest commit on main.
- When you switch to a feature branch, HEAD moves to that branch’s latest commit.
- HEAD always points to exactly one commit — never to multiple places.
HEAD can also be detached. That happens when you check out a specific commit instead of a branch. HEAD is then pointing directly at a commit, not at a branch. Git warns you because commits made in a detached state aren’t on any branch.
┌──────────────────────────────────────────────┐
│ main │
│ │ │
│ ▼ │
│ A ──► B ──► C ← HEAD (on main) │
│ │
│ After git checkout feature │
│ │
│ main │
│ │ │
│ ▼ │
│ A ──► B ──► C │
│ │
│ feature │
│ │ │
│ ▼ │
│ A ──► B ──► X ← HEAD (on feature) │
│ │
└──────────────────────────────────────────────┘
Why HEAD matters: Every Git command that says “the current branch” or “the last commit” is really using HEAD. Understanding it makes sense of everything from
git logtogit reset.
How branches work together
When you create a branch from the main codebase, you’re essentially copying everything that existed at that moment. From there, you can make unlimited changes without affecting the original.
Eventually, when your work is ready, you merge the branch back into main. It’s like bringing experimental work back to the official project.
The two-step pattern:
- Branch — create a new line of development
- Merge — bring the changes back
Everything else — rebasing, cherry-picking, rebasing — is a variation on these two.
Common branch types:
| Type | Purpose |
|---|---|
main | Stable, deployable |
feature/* | New features |
fix/* | Bug fixes |
hotfix/* | Urgent production fixes |
release/* | Preparing a release |
experiment/* | Experimental work |
Why this shape: Branches have meaning. Naming them by purpose — feature, fix, hotfix — makes the repository self-documenting.
Full Working Git Example
A complete walkthrough — building a restaurant website with feature branches.
Step 1: Initialize the repository
mkdir restaurant-website
cd restaurant-website
git init
You now have an empty repository.
Step 2: Set up the initial project structure
echo "# Restaurant Website" > README.md
echo "<html><body><h1>Welcome to Our Restaurant</h1></body></html>" > index.html
git add .
git commit -m "Initial commit: Basic website structure"
One commit on main — the base.
Step 3: Create a feature branch
git checkout -b feature/menu
echo "<h2>Our Menu</h2><ul><li>Burger</li><li>Pizza</li></ul>" >> index.html
git add index.html
git commit -m "Add basic menu items"
-b creates the branch and switches to it in one command. HEAD now points to feature/menu. The main branch is untouched.
Step 4: Continue working on the feature
echo "<h3>Appetizers</h3><ul><li>Caesar Salad</li><li>Fried Calamari</li></ul>" >> index.html
echo "<h3>Main Courses</h3><ul><li>Grilled Salmon</li><li>Beef Steak</li></ul>" >> index.html
git add index.html
git commit -m "Add menu categories and items"
Another commit on the feature branch.
Step 5: Work on another feature
git checkout main
git checkout -b feature/reservations
echo "<h2>Make a Reservation</h2><form><input type='text' placeholder='Name'></form>" >> index.html
git add index.html
git commit -m "Add reservation form"
You switched back to main, then created a second branch from it. Two independent branches now exist — each with different work.
Step 6: Return to the menu feature
git checkout feature/menu
echo "<h3>Desserts</h3><ul><li>Chocolate Cake</li><li>Tiramisu</li></ul>" >> index.html
git add index.html
git commit -m "Add dessert section to menu"
The menu branch keeps evolving independently.
Step 7: Test and merge the menu feature
git checkout main
git branch -a
git merge feature/menu
git log --oneline
git merge feature/menu brings the menu work into main. Main now includes everything from the menu branch. History shows the merge.
Step 8: Continue working on reservations
git checkout feature/reservations
echo "<p>Available times: 5pm, 6pm, 7pm, 8pm</p>" >> index.html
git add index.html
git commit -m "Add reservation time slots"
git checkout main
git merge feature/reservations
Reservations are now merged into main too. Main has menu and reservations.
Step 9: View the final result
git log --oneline --graph --all
cat index.html
The graph shows the branching and merging. index.html has everything.
Step 10: Create a bug fix branch
git checkout -b fix/menu-bug
git add index.html
git commit -m "Fix HTML structure in menu"
git checkout main
git merge fix/menu-bug
A short-lived branch for a fix. Merged immediately.
Why this example matters: It shows the actual rhythm of branch-based work — branch, commit, switch, branch, commit, merge. Every feature gets its own space, and main stays clean until work is ready.
Complete Example Session
# ============================================
# PART 1: INIT
# ============================================
mkdir restaurant-website
cd restaurant-website
git init
# [ Initialized empty Git repository ... ]
# ============================================
# PART 2: INITIAL COMMIT
# ============================================
echo "# Restaurant Website" > README.md
echo "<html><body><h1>Welcome to Our Restaurant</h1></body></html>" > index.html
git add .
git commit -m "Initial commit: Basic website structure"
# [ [main (root-commit) a1b2c3d] Initial commit ]
# ============================================
# PART 3: CREATE FEATURE BRANCH
# ============================================
git checkout -b feature/menu
# [ Switched to a new branch 'feature/menu' ]
echo "<h2>Our Menu</h2><ul><li>Burger</li><li>Pizza</li></ul>" >> index.html
git add index.html
git commit -m "Add basic menu items"
# [ [feature/menu d4e5f6g] Add basic menu items ]
# ============================================
# PART 4: CONTINUE FEATURE
# ============================================
echo "<h3>Appetizers</h3><ul><li>Caesar Salad</li><li>Fried Calamari</li></ul>" >> index.html
echo "<h3>Main Courses</h3><ul><li>Grilled Salmon</li><li>Beef Steak</li></ul>" >> index.html
git add index.html
git commit -m "Add menu categories and items"
# ============================================
# PART 5: SWITCH AND CREATE ANOTHER BRANCH
# ============================================
git checkout main
git checkout -b feature/reservations
echo "<h2>Make a Reservation</h2><form><input type='text' placeholder='Name'></form>" >> index.html
git add index.html
git commit -m "Add reservation form"
# ============================================
# PART 6: BACK TO MENU
# ============================================
git checkout feature/menu
echo "<h3>Desserts</h3><ul><li>Chocolate Cake</li><li>Tiramisu</li></ul>" >> index.html
git add index.html
git commit -m "Add dessert section to menu"
# ============================================
# PART 7: MERGE MENU
# ============================================
git checkout main
git branch -a
# [ feature/menu ]
# [ feature/reservations ]
# [ * main ]
git merge feature/menu
# [ Updating a1b2c3d..h7i8j9k ]
# [ Fast-forward ]
# [ index.html | 5 +++++ ]
# [ 1 file changed, 5 insertions(+) ]
git log --oneline
# [ h7i8j9k (HEAD -> main, feature/menu) Add dessert section to menu ]
# [ ... ]
# ============================================
# PART 8: MERGE RESERVATIONS
# ============================================
git checkout feature/reservations
echo "<p>Available times: 5pm, 6pm, 7pm, 8pm</p>" >> index.html
git add index.html
git commit -m "Add reservation time slots"
git checkout main
git merge feature/reservations
# ============================================
# PART 9: VIEW RESULT
# ============================================
git log --oneline --graph --all
# [ * merge commit ]
# [ |\ ]
# [ | * Add reservation time slots ]
# [ | * Add reservation form ]
# [ * | Add dessert section to menu ]
# [ |/ ]
# [ * Add menu categories and items ]
# [ * Add basic menu items ]
# [ * Initial commit ]
cat index.html
# (contains all merged content)
# ============================================
# PART 10: BUG FIX BRANCH
# ============================================
git checkout -b fix/menu-bug
git add index.html
git commit -m "Fix HTML structure in menu"
git checkout main
git merge fix/menu-bug
Quick Reference
Branch Commands
| Command | Purpose |
|---|---|
git branch | List local branches |
git branch -a | List all branches |
git branch NAME | Create a branch |
git checkout NAME | Switch to a branch |
git checkout -b NAME | Create and switch |
git switch NAME | Switch (modern) |
git switch -c NAME | Create and switch (modern) |
git merge NAME | Merge into current |
git branch -d NAME | Delete merged branch |
git branch -D NAME | Force delete |
HEAD
| Term | Meaning |
|---|---|
| HEAD | Pointer to current commit |
| Attached HEAD | On a branch |
| Detached HEAD | On a specific commit |
HEAD~1 | One commit back |
HEAD~N | N commits back |
Branch Naming
| Prefix | Purpose |
|---|---|
feature/ | New feature |
fix/ | Bug fix |
hotfix/ | Urgent production fix |
release/ | Release prep |
experiment/ | Experiment |
Merge Types
| Type | When |
|---|---|
| Fast-forward | Target hasn’t changed |
| Three-way | Both branches have commits |
| Squash | Combine into one commit |
Inspecting Branches
| Command | Shows |
|---|---|
git log --oneline --graph --all | Visual branch history |
git branch -v | Branch with last commit |
git branch --merged | Branches merged into current |
git branch --no-merged | Unmerged branches |
Best Practices
✅ Do This:
# Create a branch per feature
git checkout -b feature/login # ✅
# Use descriptive names
git checkout -b fix/signup-validation # ✅
# Merge back when done
git checkout main
git merge feature/login # ✅
# Delete merged branches
git branch -d feature/login # ✅
# Check status often
git status # ✅
# Use --graph to see history
git log --oneline --graph --all # ✅
❌ Don’t Do This:
# Don't work directly on main
# Use a feature branch # ❌
# Don't use vague branch names
git checkout -b stuff # ❌
# Don't force-delete unmerged branches
git branch -D feature/important # ❌ data loss
# Don't forget to merge before deleting
git branch -d feature/menu # ⚠️ if unmerged
# Don't merge without testing
git merge feature/menu # ⚠️ run tests first
# Don't leave branches lying around
# Delete merged ones # ⚠️
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
| Commit on wrong branch | Work in the wrong place | Check git status before committing |
| Forgot to switch back | Continuing on old branch | git branch shows current |
| Merge conflict | Same lines changed | Resolve, then commit |
| Detached HEAD | Commits not on a branch | Create a branch immediately |
| Deleting unmerged branch | Lost work | Use -D only when sure |
| Too many stale branches | Clutter | Delete merged ones |
| Merging without testing | Broken main | Test before merge |
Real-World Examples
1. Create a branch
git checkout -b feature/login
Creates and switches in one command.
2. Switch branches
git checkout main
Moves HEAD to main.
3. Modern switch
git switch -c feature/login
Newer syntax, same effect.
4. List branches
git branch -a
Shows local and remote branches.
5. Merge a branch
git merge feature/login
Brings changes into current branch.
6. Delete a merged branch
git branch -d feature/login
Safe delete — refuses if unmerged.
7. Force delete
git branch -D feature/old
Deletes even if unmerged.
8. Visualize history
git log --oneline --graph --all
Shows branch structure.
9. Check what’s merged
git branch --merged
Lists branches already in main.
10. Find unmerged branches
git branch --no-merged
Lists branches not yet merged.
Visual: Branching and Merging
┌──────────────────────────────────────────────┐
│ main │
│ │ │
│ A ──► B ──► C ──► D ──► F ──► G │
│ │ ▲ │
│ │ │ │
│ └──► X ──► Y ──► Z ───┘ │
│ feature/menu │
│ │
│ Feature branches split off, then merge back │
│ │
└──────────────────────────────────────────────┘
Visual: HEAD
┌──────────────────────────────────────────────┐
│ HEAD points to a commit │
│ │
│ main │
│ │ │
│ ▼ │
│ A ──► B ──► C │
│ ▲ │
│ │ │
│ HEAD │
│ │
│ When you switch branches, HEAD moves │
│ │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ Detached HEAD │
│ │
│ main │
│ │ │
│ ▼ │
│ A ──► B ──► C │
│ ▲ │
│ │ │
│ HEAD (detached) │
│ │
│ Commits made here aren't on any branch │
│ │
└──────────────────────────────────────────────┘
Visual: Fast-Forward vs Three-Way Merge
┌──────────────────────────────────────────────┐
│ Fast-forward │
│ │
│ main: A ──► B │
│ feature: A ──► B ──► C ──► D │
│ │
│ After merge: │
│ main: A ──► B ──► C ──► D │
│ │
│ Main just moves forward — no merge commit │
│ │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ Three-way merge │
│ │
│ main: A ──► B ──► E ──► F │
│ feature: A ──► B ──► C ──► D │
│ │
│ After merge: │
│ main: A ──► B ──► E ──► F ──► M │
│ │ ▲ │
│ └──► C ──► D │
│ │
│ A merge commit (M) is created │
│ │
└──────────────────────────────────────────────┘
Visual: Common Branching Workflow
┌──────────────────────────────────────────────┐
│ main │
│ │ │
│ ├──► feature/login │
│ │ │ │
│ │ └──► merged back to main │
│ │ │
│ ├──► fix/signup-bug │
│ │ │ │
│ │ └──► merged back to main │
│ │ │
│ └──► feature/dashboard │
│ │ │
│ └──► merged back to main │
│ │
│ One branch per task, merged when ready │
│ │
└──────────────────────────────────────────────┘
Summary
| Concept | Meaning |
|---|---|
| Branch | Independent line of development |
| Main | Stable, deployable branch |
| HEAD | Pointer to current commit |
| Feature branch | Isolated work for a feature |
| Merge | Combine branches |
| Fast-forward | Simple move of a pointer |
| Three-way merge | Creates a merge commit |
| Detached HEAD | HEAD on a commit, not a branch |
Key takeaways:
- A branch is a movable pointer — not a copy of the codebase
- Branches let you work on features, fixes, and experiments in isolation
- Main (formerly
master) is the stable, deployable branch - HEAD always points to your current commit — on a branch or detached
git checkout -b NAMEcreates a branch and switches to itgit switch -c NAMEis the modern equivalentgit merge NAMEbrings another branch’s changes into the current one- Merges are fast-forward (simple pointer move) or three-way (merge commit)
- Delete merged branches with
-d; force-delete with-D - Use descriptive branch names —
feature/,fix/,hotfix/ - Use
git log --oneline --graph --allto see the whole picture - Never work directly on main — always branch for changes
Remember: Branches are Git’s superpower. They’re cheap, fast, and safe. Create one per feature, isolate your work, merge when it’s tested and ready. Keep main stable. Delete branches when they’re done. And let --graph show you the shape of your history — it’s the fastest way to understand what happened.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!