Git Branches — A Practical Guide
A practical guide to Git branches — what they are, why they matter, and how to create, merge, and delete them with a real-world workflow example.
If you've worked through the Git and GitHub Beginner's Guide, you already know how to commit and push. Branches are the next concept worth understanding — and once you see why they exist, you'll wonder how you worked without them.
What a Branch Actually Is
A branch is an independent line of development. Think of it as a copy of your project at a point in time that you can work on freely without affecting anything else.
Your repository always has at least one branch — main — which represents
the stable, working version of your project. When you want to add a feature,
fix a bug, or experiment with something, you create a new branch, do your
work there, and merge it back into main when it's ready.
main: A -- B -- C ---------------- F
\ /
feature: D -- E --------Commits D and E happen on the feature branch, completely isolated from
main. When the work is done, it merges back in at F. If something goes
wrong on the feature branch, main is untouched.
Why Branches Are Necessary
Without branches, any work in progress lives on main. If you push
half-finished code, the live site breaks. If you want to try something
experimental, you risk destabilizing working code. If two people work
simultaneously, their changes collide.
With branches, each piece of work is isolated:
mainalways contains working, deployable code- Features are developed in isolation and only merged when complete
- Experiments can be abandoned without affecting anything
- Multiple people (or multiple tasks) can progress in parallel
This is exactly how the terminal feature on this site was built — a
feature/terminal branch ran for several sessions while new content
was still being published to main without interference.
The Core Commands
Create a new branch
git checkout -b feature/my-feature-b creates the branch and switches to it in one step. You're now
working on feature/my-feature — main is unchanged.
The modern equivalent using git switch:
git switch -c feature/my-featureBoth do the same thing. checkout is older and more widely documented;
switch is newer and more explicit. Either works.
See all branches
git branchThe active branch is marked with *. Add -a to also see remote branches:
git branch -aSwitch between branches
git checkout main
git checkout feature/my-featureOr with the newer syntax:
git switch main
git switch feature/my-featureBefore switching branches, make sure your working directory is clean —
either commit your changes or stash them. Uncommitted changes can
follow you between branches and cause confusion. Run git status
before switching.
Push a branch to GitHub
The first time you push a new branch:
git push -u origin feature/my-featureAfter that, just git push from that branch.
Merging
When your feature branch is ready, you merge it back into main.
git checkout main
git merge feature/my-featureTwo things can happen:
Fast-forward merge
If main hasn't changed since you branched off it, Git simply moves
main forward to include your commits. No merge commit is created —
the history stays linear.
Before: main: A -- B
\
feature: C -- D
After: main: A -- B -- C -- DMerge commit
If main has new commits that your branch doesn't have — because someone
else pushed, or you published content on main while working on the
feature — Git creates a merge commit that ties the two histories together.
Before: main: A -- B -- E
\
feature: C -- D
After: main: A -- B -- E -- F (merge commit)
\ /
feature: C -- D ----Both are valid. Fast-forward is cleaner; merge commits preserve the full branching history.
Resolving Conflicts
A conflict happens when the same part of the same file was changed on both branches. Git can't decide which version to keep — it flags the file and asks you to resolve it manually.
<<<<<<< HEAD
This is the version from main.
=======
This is the version from the feature branch.
>>>>>>> feature/my-featureTo resolve:
- Open the file and edit it — keep what's correct, remove the conflict markers
git addthe resolved filegit committo complete the merge
Conflicts sound scary but they're routine. The best way to minimize them
is to keep feature branches short-lived and merge them back frequently
rather than letting them diverge from main for a long time.
Deleting a Branch
Once a branch is merged, it's safe to delete it — the commits are now
part of main and won't be lost.
Delete locally:
git branch -d feature/my-featureGit uses -d (safe delete) which refuses to delete an unmerged branch.
Use -D (force delete) only if you're intentionally discarding unmerged
work.
Delete the remote branch on GitHub:
git push origin --delete feature/my-featureA Real Example — How This Site Uses Branches
The terminal feature on this site (the >_ button in the top right) was
built entirely on a feature branch. Here's exactly how it worked:
# Start the feature branch
git checkout -b feature/terminal
# Work across multiple sessions, committing as we go
git add .
git commit -m "Add terminal shell with basic commands"
git push origin feature/terminal
# Meanwhile, on a different day, switch to main to publish a new post
git checkout main
git add content/projects/self-hosted-ai-stack-part-3.md
git commit -m "Add AI stack part 3"
git push
# Switch back to the feature branch and keep building
git checkout feature/terminal
git add .
git commit -m "Add terminal navigation and download"
git push origin feature/terminal
# When the feature was complete and tested, merge it
git checkout main
git merge feature/terminal
git push
# Clean up
git branch -d feature/terminal
git push origin --delete feature/terminalThe live site at thedefaultgateway.com kept deploying from main
throughout — new posts went live normally while the terminal was being
built in isolation. No half-finished code ever touched the live site.
The Everyday Branch Workflow
# 1. Start from an up-to-date main
git checkout main
git pull
# 2. Create your feature branch
git checkout -b feature/your-feature
# 3. Do your work and commit regularly
git add .
git commit -m "Describe what you did"
# 4. Push to GitHub (backup + collaboration)
git push -u origin feature/your-feature
# 5. When done, merge back into main
git checkout main
git merge feature/your-feature
git push
# 6. Clean up
git branch -d feature/your-feature
git push origin --delete feature/your-featureNaming Branches
There's no enforced convention but a consistent pattern makes branches easier to understand at a glance:
| Prefix | Use for |
|---|---|
feature/ | New functionality |
fix/ | Bug fixes |
content/ | New posts or notes |
refactor/ | Code cleanup with no behavior change |
experiment/ | Exploratory work you might abandon |
Examples: feature/terminal, fix/date-sorting, content/networking-notes
Quick Reference
| Command | What it does |
|---|---|
git checkout -b <branch> | Create and switch to a new branch |
git switch -c <branch> | Same, newer syntax |
git branch | List local branches |
git branch -a | List all branches including remote |
git checkout <branch> | Switch to an existing branch |
git push -u origin <branch> | Push branch to GitHub (first time) |
git merge <branch> | Merge a branch into the current one |
git branch -d <branch> | Delete a merged branch locally |
git push origin --delete <branch> | Delete a branch on GitHub |
git status | Always run before switching branches |