Branches

A branch is an independent line of work. You create one to build a feature, fix a bug or try an idea without disturbing the main code; when it's ready, you merge it back. In Git, branches are instant and cost almost nothing, so you'll use them for nearly everything.

Why branch?

Imagine Sam is halfway through reorganising the recipe collection when someone reports a typo that needs fixing right away. Without branches, the half-finished reorganisation and the urgent fix get tangled together. With branches, the reorganisation lives on its own branch; Sam switches back to main, fixes the typo, and returns to the reorganisation later. Teams use the same idea at scale: every feature or fix is developed on its own branch and reviewed before it joins main.

Listing branches

$
git branch
Output
* main

A new repository has one branch, main. The * marks the current branch. -v adds each branch's latest commit:

$
git branch -v
Output
* main 90c0089 Add omelette recipe

Creating a branch

$
git branch desserts
git branch
Output
  desserts
* main

git branch <name> creates a branch pointing at the current commit — but it doesn't switch to it; you're still on main. Usually you want to create and switch in one go, which is git switch -c (next lesson).

What a branch really is

A branch is nothing more than a name for a commit. Git stores it as a tiny file containing a hash:

$
cat .git/refs/heads/desserts
git rev-parse main
Output
90c00895dd5f3596c58ac005e17872f41039efcb
90c00895dd5f3596c58ac005e17872f41039efcb

Both branches point at the same commit right now. When you commit on a branch, only that branch's label moves forward to the new commit; the others stay where they are:

TXT
        main, desserts                          main
              │                                  │
  A ◀── B ◀───┘          commit on desserts   A ◀── B ◀── C
                         ─────────────────▶              │
                                                      desserts

That's why creating a branch is instant, even in a huge project: nothing is copied.

Branching from another point

Add a commit or another branch name to start the new branch somewhere other than where you are:

$
git branch first-draft HEAD~1
git branch -v
Output
  desserts    90c0089 Add omelette recipe
  first-draft c4f5e47 Add pancake recipe
* main        90c0089 Add omelette recipe

Renaming

$
git branch -m first-draft archive/first-draft
git branch
Output
  archive/first-draft
  desserts
* main

git branch -m new-name with one name renames the current branch.

Deleting

-d deletes a branch, but only if its commits are safely merged somewhere. Git refuses otherwise, to protect unmerged work:

$
git branch -d desserts
Output
error: The branch 'desserts' is not fully merged.
If you are sure you want to delete it, run 'git branch -D desserts'.

If you really want to throw the work away, -D forces it. (Deleted by mistake? The reflog can bring it back; lesson 20.) A fully merged branch deletes without fuss:

$
git branch -d archive/first-draft
Output
Deleted branch archive/first-draft (was c4f5e47).

Deleting a branch only removes the label. Commits that are part of another branch remain in history.

Naming branches

Branch names can contain letters, numbers, -, _, . and /, but no spaces. Most teams adopt a pattern that says what the branch is for:

PatternExample
feature/…feature/gift-cards
fix/… or bugfix/…fix/checkout-total
With an issue number142-empty-basket-crash
With your namesam/try-new-layout

Keep names short, lowercase and descriptive. The slash is just part of the name, but many tools display such branches as folders.

Useful listings

CommandLists
git branch -aLocal and remote-tracking branches (lesson 35)
git branch --mergedBranches already merged into the current one — safe to delete
git branch --no-mergedBranches with work not yet merged
git branch --sort=-committerdateMost recently updated first
git branch --list "fix/*"Branches matching a pattern
$
git branch --no-merged
Output
  desserts

Try it yourself

Create three branches from main, commit something on one of them, then use git branch -v, --merged and --no-merged to see which is which. Delete the two that are merged with -d.