Last updated: 2026-05-17

Introduction to Branching

Branching is Git's most powerful feature and the one that sets it apart from almost every other version control system that came before it. Understanding how branches work — not just how to use the commands, but what is actually happening under the hood — makes everything else in Git fall into place.


What a Branch Actually Is

To understand branching, you need to recall how Git stores data. Every commit is a snapshot that stores a pointer to the previous commit (its parent). This chain of parent pointers forms your project history.

A branch is simply a lightweight, movable pointer to one of these commits. That is all it is — a file containing a 40-character SHA-1 hash pointing to a specific commit. Creating a branch in Git takes milliseconds and costs almost nothing, because Git is only writing 41 bytes to a file.

This is in sharp contrast to older version control systems, where branching meant copying the entire project directory — a process that could take minutes on large projects. In Git, branching is instantaneous regardless of project size.

When you make commits on a branch, the branch pointer moves forward automatically to point to the newest commit. The branch always reflects the latest state of work on that line of development.


HEAD — Where You Are Right Now

Git uses a special pointer called HEAD to track which branch you are currently on. HEAD always points to the branch you have checked out — and the branch points to the latest commit on that branch.

When you make a new commit:

  1. Git creates the commit with the current commit as its parent.
  2. The branch pointer moves forward to the new commit.
  3. HEAD continues to point to the branch.
HEAD → main → commit C

When you switch branches, HEAD moves to point to the new branch, and your working directory is updated to match the state of that branch's latest commit.


Creating a Branch — git branch

To create a new branch:

git branch feature-login

This creates a new pointer called feature-login pointing to the same commit you are currently on. Importantly, it does not switch you to the new branch — HEAD still points to your original branch.

To see all branches and which one you are on:

git branch
  feature-login
* main

The * marks the branch HEAD is currently pointing to — the branch you are on.


Switching Branches — git switch and git checkout

To move to a different branch:

git switch feature-login     # Modern syntax (Git 2.23+)
git checkout feature-login   # Older syntax — still works

When you switch branches, Git does two things:

  1. Moves HEAD to point to the new branch.
  2. Updates the working directory to match the snapshot that branch points to — adding, removing, and modifying files automatically.

Important: Switching branches changes the files in your working directory. If you switch to an older branch, your files will look exactly as they did the last time you committed on that branch. If you have uncommitted changes that conflict with the branch you are switching to, Git will refuse to switch until you deal with them — either by committing or stashing the changes.


Creating and Switching in One Step

The most common pattern is creating a branch and immediately switching to it:

git switch -c feature-login       # Modern syntax
git checkout -b feature-login     # Older syntax

Both are shorthand for:

git branch feature-login
git switch feature-login

Use git switch -c in new work — it is cleaner and more explicit in its intent.


How Branches Diverge

The real power of branching becomes clear when you understand divergence. Once you switch to a new branch and make commits, the histories of the two branches diverge — each branch moves independently forward from a shared common ancestor.

# Start on main, create a feature branch
git switch -c feature-login

# Make commits on feature-login
git commit -m "Add login form"
git commit -m "Add authentication logic"

# Switch back to main
git switch main

# Make a different commit on main
git commit -m "Fix homepage typo"

At this point the history looks like this:

      A -- B -- C  (main)
           \
            D -- E  (feature-login)

The two branches share commits up to B, then diverge. Each branch has its own independent line of development. Changes on feature-login have no effect on main and vice versa — until you decide to merge them.

You can visualise this directly:

git log --oneline --graph --all
* c3f4d1a (HEAD -> main) Fix homepage typo
| * e8a21bc (feature-login) Add authentication logic
| * d7b903f Add login form
|/
* f30ab12 Previous commit

Why Branching Matters

Before Git made branching cheap and instant, most teams avoided it because the cost was too high. Git changed the economics completely.

The standard modern workflow uses branches for every piece of isolated work:

  • Feature branches — each new feature lives on its own branch, developed independently from the main codebase.
  • Bug fix branches — urgent fixes are created as short-lived branches off the stable main branch.
  • Experimental branches — speculative ideas can be explored freely and thrown away if they don't work out, with no impact on anything else.

Because creating and deleting branches is instant and free, the practice of branching often — even multiple times per day — is not just possible but actively encouraged. It keeps work isolated, history clean, and collaboration safe.


Basic Branch Commands

List branches

git branch              # Local branches
git branch -v           # Local branches with last commit
git branch -a           # All branches including remote-tracking

Create a branch

git branch <name>             # Create without switching
git switch -c <name>          # Create and switch

Switch branches

git switch <name>             # Switch to existing branch
git switch -                  # Switch back to the previous branch

Delete a branch

git branch -d <name>          # Delete a merged branch (safe)
git branch -D <name>          # Force delete an unmerged branch

Deleting a branch only removes the pointer — it does not delete any commits. If the branch was merged, those commits remain accessible through the branch they were merged into.

Rename a branch

git branch -m <old> <new>     # Rename a local branch

The --decorate Flag

When viewing history, the --decorate flag (included by default in --oneline) shows where each branch pointer and HEAD are currently sitting:

git log --oneline --decorate
f30ab (HEAD -> main, feature-login) Add feature
34ac2 Fix bug
98ca9 Initial commit

This shows that both main and feature-login are pointing to the same commit, and HEAD is on main.


Summary

CommandWhat It Does
git branchLists all local branches
git branch <name>Creates a new branch
git branch -vLists branches with last commit
git branch -d <name>Deletes a merged branch
git branch -D <name>Force-deletes a branch regardless of merge status
git switch <name>Switches to an existing branch
git switch -c <name>Creates a branch and switches to it
git switch -Switches back to the previous branch
git checkout <name>Switches to a branch (older syntax)
git checkout -b <name>Creates and switches to a branch (older syntax)
git log --oneline --graph --allVisualises the full branch history