← Back to Notes

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:

  • main always 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-feature

Both do the same thing. checkout is older and more widely documented; switch is newer and more explicit. Either works.

See all branches

git branch

The active branch is marked with *. Add -a to also see remote branches:

git branch -a

Switch between branches

git checkout main
git checkout feature/my-feature

Or with the newer syntax:

git switch main
git switch feature/my-feature
W
WARN

Before 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-feature

After 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-feature

Two 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 -- D

Merge 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-feature

To resolve:

  1. Open the file and edit it — keep what's correct, remove the conflict markers
  2. git add the resolved file
  3. git commit to complete the merge
T
TIP

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-feature

Git 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-feature

A 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/terminal

The 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-feature

Naming Branches

There's no enforced convention but a consistent pattern makes branches easier to understand at a glance:

PrefixUse 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

CommandWhat it does
git checkout -b <branch>Create and switch to a new branch
git switch -c <branch>Same, newer syntax
git branchList local branches
git branch -aList 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 statusAlways run before switching branches

Related