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-gatewayto 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 branchIn 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 commitsA 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 testsBoth 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/fooand the remoteorigin/feature/fooare two different things — they happen to share a name.git branchshows local;git branch -ashows 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.
- In your local clone of any active project (or clone
https://github.com/cypress-io/cypress.git), rungit branch. Note the asterisk onmain(ormasterfor older repos). - Run
git branch -a. Count how many remote branches exist. On a busy project there will be dozens. - Pick one remote branch and check it out:
git checkout <branch-name>. Rungit log --oneline | head -5. Notice the recent commits differ frommain's. - Switch back:
git checkout main. Rungit log --oneline | head -5. Different commits — you teleported between two timelines. - 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. - 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.