Branching Fundamentals

Branching Fundamentals

Branching Basics

Introduction

Branches are one of Git's most powerful features and what truly sets it apart from older version control systems. A branch allows you to diverge from the main line of development and work independently without affecting the stable code. Once your work is ready, you can merge it back in.

Think of branches like parallel universes for your code. In one universe, you're adding a new feature. In another, the code is stable and running in production. You can switch between these universes instantly, and eventually, you can merge them together.

This lesson will teach you how to create, switch between, and manage branches effectively.

What is a Branch?

A branch is simply a pointer to a specific commit in your project's history. When you create a new branch, Git creates a new pointer—it doesn't create a new copy of all your files. This makes branching in Git incredibly fast and lightweight.

The Default Branch

When you initialize a repository, Git creates a default branch. This is typically called "main" (in newer Git versions) or "master" (in older versions). This branch usually represents the stable, production-ready version of your code.

Why Branch?

Imagine you're working on a website that's live in production. You want to add a new feature, but it will take several days of work. You don't want to break the live site while developing. The solution is to create a branch:

  • The main branch stays stable and deployable
  • Your feature branch contains the experimental work
  • You can switch between them anytime
  • When the feature is complete and tested, you merge it back to main

This workflow lets you work on multiple features simultaneously without them interfering with each other.

Viewing Existing Branches

Before creating new branches, let's see what branches exist in your repository.

List all local branches:

git branch

Output:

* main
  feature-login
  bugfix-header

The asterisk (*) indicates your current branch. In this example, you're on the "main" branch.

List all branches with more details:

git branch -v

Output:

* main           d8c5f1a Add contact form validation
  feature-login  a3f2e9b Implement login UI
  bugfix-header  7f1a3d5 Fix header alignment

This shows the last commit on each branch.

List remote branches:

git branch -r

Shows branches that exist on your remote repository (like GitHub).

List all branches (local and remote):

git branch -a

Creating Branches

Creating a branch is simple and instantaneous. Remember, you're just creating a new pointer to a commit—Git doesn't copy your entire project.

Create a new branch:

git branch feature-navbar

This creates a branch called "feature-navbar" pointing to your current commit. However, you're still on your original branch—creating a branch doesn't automatically switch to it.

Verify the branch was created:

git branch

Output:

  feature-navbar
* main

The new branch exists, but you're still on "main" (indicated by the asterisk).

Branch Naming Conventions

Good branch names are descriptive and follow a consistent pattern. Common conventions include:

Feature branches:

  • feature/user-authentication
  • feature-shopping-cart
  • add-dark-mode

Bug fix branches:

  • bugfix/login-error
  • fix-memory-leak
  • hotfix-payment-gateway

Experimental branches:

  • experiment/new-ui
  • test-performance-optimization

Use descriptive names - Anyone should understand what the branch is for without asking.

Use hyphens or slashes - Avoid spaces or special characters. feature-login or feature/login are good. feature login or feature#login are problematic.

Be concise but clear - feature-user-auth is better than feature-user-authentication-system-with-jwt-tokens.

Switching Branches

Once you've created a branch, you need to switch to it to start working on it.

Switch to an existing branch (modern syntax):

git switch feature-navbar

Output:

Switched to branch 'feature-navbar'

Your working directory now reflects the state of the "feature-navbar" branch.

Switch to an existing branch (classic syntax):

git checkout feature-navbar

Both commands do the same thing. git switch is newer and more intuitive, while git checkout is the traditional command that does many things.

Verify you switched:

git branch

Output:

* feature-navbar
  main

The asterisk moved to "feature-navbar"—you're now on that branch.

What Happens When You Switch?

When you switch branches, Git does three things:

  1. Changes the files in your working directory to match the branch's latest commit
  2. Updates the staging area to match that commit
  3. Moves the HEAD pointer to point at the new branch

If you have uncommitted changes, Git will try to preserve them when switching. However, if the changes would conflict with files in the target branch, Git will refuse to switch and ask you to commit or stash your changes first.

Creating and Switching in One Command

You'll often want to create a branch and immediately switch to it. There's a shortcut for this:

Create and switch (modern syntax):

git switch -c feature-contact-form

The -c flag means "create."

Create and switch (classic syntax):

git checkout -b feature-contact-form

The -b flag means "create a new branch."

Both commands create "feature-contact-form" and switch to it immediately.

Working on a Branch

Once you're on a branch, your normal workflow continues:

# Make changes to files
echo "New feature code" > feature.js

# Stage changes
git add feature.js

# Commit changes
git commit -m "Add new feature"

These commits only affect the current branch. The main branch remains unchanged.

See commits on current branch:

git log --oneline

Compare with main branch:

git log main..feature-navbar --oneline

This shows commits that exist on "feature-navbar" but not on "main"—the work you've done in this branch.

Understanding Branch Divergence

As you work on a branch, other team members might be pushing commits to the main branch. Your branch and main begin to diverge—they have different recent histories.

Visualize branch structure:

git log --oneline --graph --all

Output might look like:

* a7d3c2f (HEAD -> feature-navbar) Add navbar styling
* 3e8b1d4 Create navbar component
| * d8c5f1a (main) Fix footer bug
| * 7f2e9b3 Update homepage content
|/
* 4b6c8a1 Initial commit

This shows that "feature-navbar" has two commits, and "main" has two different commits. They both started from the same point but have diverged.

This is perfectly normal and one of branching's key benefits. You can work independently while others work on main.

Switching Back to Main

You can switch between branches as often as you like:

git switch main

Your working directory now shows the state of the main branch. The changes you made in "feature-navbar" aren't visible here—they still exist in that branch, waiting for you to return.

Switch back to feature branch:

git switch feature-navbar

Your feature work reappears. Nothing was lost—it was always safely stored in the branch.

Deleting Branches

Once a feature is complete and merged (we'll cover merging in the next lesson), you should delete the branch to keep your repository clean.

Delete a merged branch:

git branch -d feature-navbar

Git will only allow this if the branch has been fully merged. This protects you from accidentally deleting unmerged work.

Force delete an unmerged branch:

git branch -D experimental-feature

The capital -D force deletes the branch even if it hasn't been merged. Be careful—this can lose work if the branch hasn't been merged or pushed anywhere.

Delete a remote branch:

git push origin --delete feature-navbar

This removes the branch from your remote repository (like GitHub).

Renaming Branches

If you made a typo or want to change a branch name:

Rename current branch:

git branch -m new-branch-name

Rename a different branch:

git branch -m old-name new-name

If the branch has been pushed to a remote, you'll need to delete the old name remotely and push the new name:

git push origin --delete old-name
git push origin new-name

Branch Workflows

Different teams use different branching strategies. Here are common patterns:

Feature Branch Workflow

Each feature gets its own branch:

git switch -c feature-shopping-cart
# Work on shopping cart
git commit -am "Add shopping cart"

git switch main
git switch -c feature-user-profile
# Work on user profile
git commit -am "Add user profile"

Each feature is isolated. You can work on multiple features simultaneously and merge them independently.

Gitflow Workflow

A more structured approach with different branch types:

  • main - Production-ready code
  • develop - Integration branch for features
  • feature/* - Individual features branch from develop
  • release/* - Preparing a new release
  • hotfix/* - Emergency fixes to production

This is more complex but scales well for larger teams.

Trunk-Based Development

Everyone commits to one main branch (the "trunk"), using very short-lived feature branches or committing directly:

git switch -c quick-fix
# Make small change
git commit -am "Fix typo"
git switch main
# Merge immediately

This requires good automated testing and continuous integration.

Practical Branching Scenarios

Scenario 1: Starting a New Feature

You're working on a website and need to add a blog section:

git switch main                    # Start from stable code
git pull                           # Get latest changes
git switch -c feature-blog         # Create feature branch
# ... work on blog ...
git add .
git commit -m "Add blog listing page"
git commit -m "Add blog post page"
git commit -m "Add blog navigation"

Your blog feature is isolated from main. If a critical bug appears in production, you can switch back to main, fix it, and return to your feature work.

Scenario 2: Switching Context

You're mid-feature when a bug report comes in:

git status                         # Check if you have uncommitted changes
git commit -am "WIP: blog styling" # Commit work in progress
git switch main                    # Switch to main
git switch -c bugfix-login         # Create bug fix branch
# ... fix the bug ...
git commit -am "Fix login timeout issue"
# ... merge the fix ...
git switch feature-blog            # Return to feature work
# Continue where you left off

Branches let you context-switch without losing work or mixing unrelated changes.

Scenario 3: Experimenting Safely

You want to try a risky refactoring:

git switch -c experiment-refactor  # Create experimental branch
# ... make dramatic changes ...
git commit -am "Try new architecture"
# Test it out
# If it works: merge it
# If it doesn't: git switch main; git branch -D experiment-refactor

The experiment happens in isolation. If it fails, delete the branch and no harm is done.

Common Pitfalls and How to Avoid Them

Uncommitted Changes When Switching

If you try to switch branches with uncommitted changes that would conflict:

error: Your local changes to the following files would be overwritten by checkout:
    index.html
Please commit your changes or stash them before you switch branches.

Solutions:

  1. Commit your changes first
  2. Stash your changes (temporarily save them): git stash
  3. Discard changes (if they're not needed): git restore .

Forgetting Which Branch You're On

Always check before making commits:

git branch        # Shows current branch
git status        # Also shows current branch

Many developers customize their terminal prompt to always show the current branch name.

Creating Branches from the Wrong Starting Point

Always switch to the branch you want to start from before creating a new branch:

git switch main                    # Start from main
git pull                           # Get latest changes
git switch -c feature-new          # Create branch from main

If you create a branch from the wrong place, you'll include unrelated commits.

Deleting Unmerged Branches Accidentally

Git protects you with -d, but double-check before using -D:

git branch -d feature-test         # Safe: won't delete if unmerged
git branch -D feature-test         # Dangerous: force deletes

Before force deleting, verify the branch is truly unwanted.

Checking Branch Status

See which branches are merged into current branch:

git branch --merged

Lists branches that have been completely merged. These are safe to delete.

See which branches aren't merged:

git branch --no-merged

Lists branches with unmerged work. Be careful deleting these.

See last commit on each branch:

git branch -v

Helps identify stale branches that might need cleanup.

Remote Branches

When working with remote repositories (like GitHub), you'll encounter remote branches.

See remote branches:

git branch -r

Output:

origin/main
origin/feature-login
origin/feature-navbar

Create local branch from remote:

git switch -c feature-login origin/feature-login

Or more simply (Git will figure it out):

git switch feature-login

Push local branch to remote:

git push -u origin feature-navbar

The -u flag sets up tracking, so future git push and git pull commands know where to push/pull from.

We'll cover remote branches in more detail in a future lesson on collaboration.

Best Practices

Branch often - Branches are cheap. Create them liberally for features, bugs, experiments.

Keep branches short-lived - Long-lived branches are harder to merge. Aim to merge within days, not weeks.

Branch from the right place - Usually from main or develop. Ensure your starting point is up to date.

Use descriptive names - Future you will appreciate clear branch names.

Delete merged branches - Keep your branch list clean. Delete branches after merging.

Commit before switching - Avoid conflicts by committing or stashing before switching branches.

Pull before creating branches - Start with the latest code to avoid merge conflicts later.

Summary

Branches are lightweight pointers that let you work on features independently. Key commands:

  • git branch - List branches
  • git branch feature-name - Create a branch
  • git switch branch-name - Switch to a branch
  • git switch -c feature-name - Create and switch in one command
  • git branch -d branch-name - Delete a merged branch
  • git log --graph --all - Visualize branch structure

Branching is central to Git's power. It enables parallel development, safe experimentation, and organized feature work. Master branching, and you'll unlock Git's full potential.

In the next lesson, we'll learn how to merge branches—bringing your feature work back into the main codebase. Understanding merging is essential for completing the branching workflow and collaborating effectively with others.