What Are Branches and Why They Matter

7 min read

In Chapter 1 you committed everything to a single line of history called main. That works for a solo project, but the moment two people are working on the same repo it falls apart — every change collides, every experiment risks the shared codebase, and nothing can be tried in isolation. The fix is branches: parallel versions of the project that can grow independently and be combined later. This lesson covers what a branch actually is, why QA engineers live and die by them, and the commands to inspect the ones in your repo.

A branch, in one paragraph

A branch is a parallel timeline inside the same repository. Each branch has its own commits, its own files, and its own history — but they all live in the same .git database, so switching between them is instant. Imagine a workshop with multiple workbenches. The main bench holds the finished product; you take a copy to a side bench, experiment freely, and only return to the main bench when your work is done and tested. If your experiment fails, the main product is untouched.

Internally, a branch is just a tiny pointer to a commit — that's it. Creating a branch doesn't copy any files; it copies a 40-character hash. That's why making a new branch is instant even on a 5GB repo with ten years of history.

The main branch

Every repo has one default branch. By convention (and by your Lesson 2 config) it's called main. main represents the stable, working version — the code that's currently in production, currently being deployed, or currently passing all tests. The team rule, baked into virtually every Git workflow on earth, is: never break main.

You don't break main by being careful. You break main by working only on main. The discipline is: any non-trivial change happens on its own branch first, gets reviewed, and only then merges into main. Branches are the safety net that makes the rule enforceable.

Why branches matter for QA

Test work happens on branches just as much as feature work:

  • Developers branch features. A developer creates feature/payment-gateway to build a new feature. You test on that branch — pulling it down, running the suite, finding bugs — before it merges to main. By the time it lands on main, it's already been tested.
  • You branch your test work. New regression tests, new fixtures, framework upgrades, CI tweaks — each gets its own branch. test/add-checkout-regression-suite, bugfix/stabilise-flaky-search-test, chore/upgrade-cypress-to-13.
  • Branches isolate risk. If your new test setup breaks something, only your branch is broken. Main is fine. Your teammates pulling main aren't blocked.
  • Branches enable parallel work. Three QA engineers can each work on their own branch at the same time without stepping on each other. They merge in turn, each reviewing the others' work.
  • Pull requests live on branches. Every code review happens on a branch. No branch, no PR, no review.

Inspecting branches

Open any repo and run:

git branch

In a fresh clone you'll see something like:

* main

The asterisk (*) marks the branch you're currently on. To see all branches, including ones on the remote:

git branch -a
* main
  remotes/origin/HEAD -> origin/main
  remotes/origin/feature/payment-gateway
  remotes/origin/feature/search-improvements
  remotes/origin/main

Anything starting with remotes/origin/ is a branch that exists on GitHub but you haven't checked out locally yet. Useful when a teammate says "look at my branch" — you don't have to ask the URL, you can see it right there.

To find which branches are merged into main (safe to delete) and which still have unmerged work:

git branch --merged main      # already merged into main
git branch --no-merged main   # still has unique commits

A real QA scenario

A developer says: "I just pushed feature/payment-gateway — could you write tests for it?" Your sequence:

git fetch                                    # see new branches from the remote
git branch -a | grep payment                 # confirm it's there
git checkout feature/payment-gateway         # jump onto their branch
# ...read their changes, run their app, find bugs...
git checkout -b test/payment-gateway-tests   # branch off to write your tests

Both branches now exist independently. The dev keeps iterating on theirs; you build tests on yours. When both are ready, both merge to main and the feature ships with tests in place.

How branches grow over time

Both lines (main and the feature branch) grow at their own pace, then meet at the merge. The repo retains both histories.

Why branches feel weirdly cheap

In older systems, "making a branch" meant duplicating an entire codebase on the server. It took minutes and cost real disk space, so teams used branches sparingly. In Git, a branch is one pointer in a 41-byte file. Make 50 branches a day if you want — Git won't notice. That cheapness is what enables every modern Git workflow; if branching were expensive, none of this would work.

⚠️ Common mistakes

  • Working directly on main. Skipping the branch step is the #1 beginner mistake. Once your half-finished change is on main, it's in the line of history everyone shares — there's no clean "set this aside" anymore. Branch first, then edit.
  • Letting branches live for weeks. A branch that diverges from main for two weeks is a merge-conflict factory. Short-lived branches (hours to a few days) merge cleanly; long-lived ones don't. Plan smaller pieces of work, ship faster.
  • Confusing local and remote branches. Your local feature/foo and the remote origin/feature/foo are two different things — they happen to share a name. git branch shows local; git branch -a shows both. Knowing which one you're looking at saves real confusion in Chapter 3.

🎯 Practice task

Inspect a real repo's branch landscape. 15-20 minutes.

  1. In your local clone of any active project (or clone https://github.com/cypress-io/cypress.git), run git branch. Note the asterisk on main (or master for older repos).
  2. Run git branch -a. Count how many remote branches exist. On a busy project there will be dozens.
  3. Pick one remote branch and check it out: git checkout <branch-name>. Run git log --oneline | head -5. Notice the recent commits differ from main's.
  4. Switch back: git checkout main. Run git log --oneline | head -5. Different commits — you teleported between two timelines.
  5. Run git branch --no-merged main. These are branches with work that hasn't reached main yet — exactly the open work in flight on the team.
  6. Stretch: read the Git for QA cheat sheet section on branches and bookmark it for the rest of this chapter.

The next lesson moves from inspecting branches to creating, switching, and deleting them — the day-to-day mechanics.

// tip to track lessons you complete and pick up where you left off across devices.