Branch Basics: Create, Switch, Merge
Master branch basics: create, switch, merge in Git. Step-by-step tutorial with hands-on exercises, troubleshooting, and next steps for distributed collaboration.
Focus: branch basics: create, switch, merge
You’ve been committing happily on main, and everything feels fine. Then the day comes: you need to experiment with a wild refactor, fix a hot bug, or build a new feature that will take days — and you can’t afford to break everything you’ve already done. The pain is real: every commit you make on main is shared, and one wrong move can ripple through the whole team. That’s the moment you stop treating Git as a simple snapshot machine and start using its superpower: branches. In this lesson, you’ll learn the branch basics you need every day — creating, switching, and merging — so you can work fearlessly, keep your history clean, and make collaboration painless.
The problem this lesson solves
Without branches, every developer on a project commits to the same shared timeline. That means:
- No isolation — Your half-finished feature sits right next to the release-ready code.
- No parallel work — Two people touching different parts of the same file create constant merge chaos.
- Fear of experimentation — One bad idea can poison the entire project history.
Branches solve this by letting you create independent lines of development. A branch is just a lightweight movable pointer to a specific commit. Creating a branch costs almost nothing — it’s not a copy of your files, it’s a label. You can create dozens of branches and switch between them at will, committing freely in each one, and merge them back together only when you’re ready.
Why this matters now: You’ve already mastered committing and viewing history. Branches are the natural next step — they let you shape that history without fear. Every serious Git workflow, from GitHub Flow to GitFlow, is built on branch basics.
Core concept / mental model
Think of Git’s commit history as a tree. The trunk is your main line (often main or master). A branch is a twig that grows from a particular commit. You can grow the twig as long as you like, add leaves (commits), and then either graft it back onto the trunk or let it die.
Here’s the key mental model:
- Commit — A snapshot of your files with a unique ID.
- Branch — A named pointer to a commit. When you make a new commit, the branch moves forward.
- HEAD — A pointer that marks which branch you’re currently on. When you switch branches, Git updates HEAD and changes the files in your working directory to match that branch’s latest commit.
Branch creation is instant: git branch <name> just creates a new pointer at your current commit. Switching is also fast: git switch <name> updates HEAD and your working directory. Merging is the act of combining the history of one branch into another — Git takes the two lines of commits and creates a new commit that joins them.
Think of branches like bookmarks in a book — they don’t duplicate the story, they just mark different places. You can jump to any bookmark, read a few pages, then jump back.
How it works step by step
Step 1: Create a branch
To create a branch named feature/login, run:
git branch feature/login
This creates a pointer at your current commit. You’re still on main — the new branch exists, but you haven’t switched to it. Verify with git branch (lists branches, asterisk marks current).
Step 2: Switch to the branch
Newer Git encourages the switch command (Git 2.23+):
git switch feature/login
Now HEAD points to feature/login, and your working directory files are updated to match that branch’s latest commit. Important: if you have uncommitted changes, Git may refuse to switch if they conflict — see Troubleshooting below.
Shortcut: Create and switch in one command:
git switch -c feature/login
Step 3: Commit on the branch
Make your changes, stage, and commit normally. Your commits go only to feature/login. main stays untouched.
Step 4: Merge the branch back
When your feature is done, switch back to the target branch (usually main) and merge:
git switch main
git merge feature/login
Git will try to automatically combine changes. If both branches changed the same lines, you’ll hit a merge conflict — see Troubleshooting.
Pro tip: Always merge into the branch that should receive the changes. Never merge
maininto a feature unless you specifically want to sync it.
Hands-on walkthrough
Let’s build a real example step by step. Create a fresh repo and follow along.
1. Set up a workspace
mkdir git-branch-demo && cd git-branch-demo
git init
echo "Hello, world" > app.py
git add app.py
git commit -m "Initial commit"
Author: you@example.com
Date: ...
Initial commit
git branch
# * main
2. Create and switch to a feature branch
git switch -c feature/greeting
# Switched to a new branch 'feature/greeting'
Edit app.py to change the greeting:
echo "Hello from the feature branch" > app.py
git add app.py && git commit -m "Update greeting"
3. Switch back to main and see the difference
git switch main
cat app.py
# Hello, world
Your change is safe on feature/greeting, and main stays clean.
4. Merge the feature branch
git merge feature/greeting
# Updating 5f9d...a3c2
# Fast-forward
# app.py | 2 +-
# 1 file changed
Now main has the updated greeting.
Note: Because
mainhadn’t moved, Git could do a fast-forward merge — it just movedmainforward to the tip of the feature branch. Ifmainhad new commits, you’d get a merge commit instead.
5. Verify the merged history
git log --oneline --graph
# * a3c2 (HEAD -> main) Update greeting
# * 5f9d Initial commit
Compare options / when to choose what
| Approach | When to use | Pros | Cons |
|---|---|---|---|
git branch + git switch |
Classic, explicit flow | Works everywhere, clear steps | Two commands per branch switch |
git switch -c |
Fast, everyday creation | One command, fewer mistakes | Requires Git 2.23+ |
git checkout -b |
Legacy scripts/older Git | Backward compatible | Mixing checkout concerns (files + branches) can confuse |
git merge with fast-forward |
Linear, simple feature branches | Cleanest history | Not possible if parent branch has diverged |
git merge --no-ff |
Team workflows that want merge commits | Preserves feature history | More commits, slightly larger log |
Choosing the right merge mode: If you prefer a linear history (every commit on a single line), fast-forward merges are ideal — but they only work when the target branch hasn’t moved since the branch point. If you want to preserve the fact that a feature branch existed, use --no-ff to force a merge commit even when fast-forward is possible.
When to create branches: Create a new branch for any feature, bugfix, or experiment that will take more than one commit. For trivial one-line fixes, staying on main is often fine — but for anything that could destabilize, branch first.
Pro tip: Name your branches with a convention (e.g.,
feature/,bugfix/,hotfix/). It makes the history readable and helps CI/CD tools target the right branches.
Troubleshooting & edge cases
Error: “Your local changes would be overwritten by checkout”
You tried to switch branches but have uncommitted changes that conflict with the target branch. Git refuses to overwrite them. Fix by committing, stashing, or discarding (if safe):
# Commit the changes first
git add . && git commit -m "WIP"
# Or stash them
git stash
git switch feature
# ... later, restore stash
git stash pop
Merge conflict: “CONFLICT (content): Merge conflict in app.py”
Both branches changed the same area of a file. Git marks the file with conflict markers:
<<<<<<< HEAD
Hello from main
=======
Hello from feature
>>>>>>> feature/greeting
Edit the file to keep what you want, remove the markers, then complete the merge:
git add app.py
git commit -m "Resolve merge conflict"
Detached HEAD
If you accidentally check out a commit hash directly (e.g., git checkout a3c2f1), Git puts you in detached HEAD — you’re not on any branch. Any new commits are “floating”. To fix, create a branch or switch back to a named branch.
Accidentally merged the wrong branch
If you merged before you were ready and haven’t pushed, you can undo the merge with git reset --hard <commit-before-merge> (use --hard with caution — it discards uncommitted changes).
What you learned & what's next
You now have the core branch skills: creating branches with git branch or git switch -c, switching between them with git switch, and merging them back with git merge. You understand the mental model of branches as pointers, how HEAD tracks your current branch, and you can handle the two most common errors: overwrite warnings and merge conflicts. You can confidently isolate work, experiment without risk, and integrate changes when they’re ready.
What’s next: In the next lesson, you’ll expand from local branches to remote branches — pushing branches to a shared repository, tracking remote refs like origin/main, and pulling others’ work with git pull. That’s where branch basics meet real-world collaboration. You’ll also explore advanced merge strategies like rebasing to keep history clean. Practice these basics with your own repos, and you’ll be ready for distributed teamwork.
Practice recap
In your own sandbox repo, create two feature branches from the same starting commit. Make one change on each, then switch back and forth to see how your working directory changes. Merge one branch back into main, and then force a conflict by editing the same line on both branches. Resolve the conflict, then push your branch to a GitHub remote and open a pull request.
Common mistakes
- Forgetting to switch to the target branch before merging — you merge into the branch you're currently on, not the branch you're thinking about.
- Using
git branchwithout switching, then wondering why your commits aren't on the new branch. - Trying to switch branches with uncommitted changes that conflict — Git will refuse, and beginners often panic or lose work instead of using
git stash. - Leaving a branch unmerged and switching away, then losing track of it — either merge it or note it in
git branch -v.
Variations
- Use the older
git checkout -bto create and switch in one command if you're on Git before 2.23 or in a script that checks out many repos. - Use
git switch --detachto deliberately go into a detached HEAD state to inspect old commits — but avoid committing there. - Use
git merge --no-ffin team workflows to force a merge commit and preserve the feature branch's shape in history.
Real-world use cases
- A developer creates a
feature/refactor-authbranch to rewrite authentication, leavingmainstable and safe for colleagues. - A hotfix branch
hotfix/security-patchis branched frommain, merged, and deployed within minutes without affecting ongoing feature work. - A code reviewer checks out a pull request branch locally to test it before merging, then switches back to their own work.
Key takeaways
- Branches are lightweight pointers to commits — creating one is instant and does not copy files.
- Use
git switch -cto create and switch in one;git branchalone just creates and stays on the current branch. - HEAD always points to your current branch — switching updates both HEAD and your working directory to match that branch's tip.
- Merging brings the changes from one branch into the branch you're currently on; fast-forward merges only happen when the target hasn't diverged.
- Merge conflicts happen when both branches edit the same lines — resolve them manually, then commit to finish the merge.
- Always check which branch you're on before committing or merging with
git branchorgit status.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.