Home Module 16 Branching & Merging

Introduction

A branch is a parallel version of your repository. By default you work on a branch called main. When you want to add a new feature or fix a bug, you create a new branch, do the work there, and then merge it back into main when it's ready.

This means main always contains working, tested code. Features are developed in isolation. If a feature turns out to be wrong, you just delete the branch — nothing in main is affected.

main:    A───B───────────────────E
               \               /
feature:        C───D (new work)

Branch Commands

List, create, and switch branches

# List all local branches (* marks current branch)
git branch

# Create a new branch
git branch feature/navigation

# Switch to a branch
git switch feature/navigation

# Create AND switch in one command (most common)
git switch -c feature/navigation

# Older syntax (still works)
git checkout -b feature/navigation

Rename and delete branches

# Rename the current branch
git branch -m new-name

# Delete a merged branch (safe)
git branch -d feature/navigation

# Force delete an unmerged branch (destructive)
git branch -D feature/navigation

See which branch you are on

git status
# On branch feature/navigation

git branch
# * feature/navigation
#   main

Merging

When your feature is done, merge it back into main:

# Step 1: Switch to the branch you want to merge INTO
git switch main

# Step 2: Merge the feature branch
git merge feature/navigation
# Output: Fast-forward (or Merge commit)

Fast-forward merge

If main hasn't changed since you branched off, Git does a fast-forward merge — it simply moves the main pointer forward to the feature branch tip. Clean and simple.

Before:  main: A───B
                    \
          feature:   C───D

After merge:  main: A───B───C───D

Three-way merge

If both branches have new commits since they diverged, Git creates a merge commit that combines both histories:

Before:  main:    A───B───E
                      \
          feature:     C───D

After merge:  main: A───B───E───M  (M = merge commit)
                         \      /
                          C───D

Merge Conflicts

A conflict happens when two branches have changed the same lines of the same file. Git cannot decide which version to keep, so it asks you.

# After a conflicting merge:
git status
# both modified: index.html

Open the conflicted file. Git marks the conflict like this:

<<<<<<< HEAD
<h1>Welcome to My Site</h1>
=======
<h1>Hello World</h1>
>>>>>>> feature/navigation

The section between <<<<<<< HEAD and ======= is what your current branch has. The section between ======= and >>>>>>> is what the incoming branch has.

Resolving a conflict

  1. Edit the file to keep the version you want (delete the conflict markers).
  2. Run git add index.html to mark it as resolved.
  3. Run git commit to complete the merge.
# The resolved file might look like:
<h1>Welcome to My Site</h1>

# Then:
git add index.html
git commit   # Git pre-fills a merge commit message
VS Code has built-in merge conflict resolution. Open the conflicted file and click "Accept Current Change", "Accept Incoming Change", or "Accept Both Changes" above each conflict block.

Rebasing (Alternative to Merging)

Instead of creating a merge commit, git rebase replays your branch's commits on top of the target branch — producing a linear history.

# While on feature branch:
git rebase main

# This replays feature commits on top of latest main
Before:  main:    A───B───E
                      \
          feature:     C───D

After rebase:  main:    A───B───E
                                \
               feature:          C'───D' (new commit hashes)
Never rebase branches that have been pushed to a shared remote. Rebasing rewrites commit hashes, which breaks history for anyone who has the old commits.

Common Mistakes

  • Committing directly to main. Always work on a feature branch. Even on solo projects, branches protect your working code.
  • Forgetting to switch branches before starting work. Run git status to confirm which branch you are on.
  • Deleting a branch before merging it. Use git branch -d (not -D) to get a warning if unmerged work would be lost.
  • Panicking at merge conflicts. Conflicts look scary but are just text markers. Read each conflict carefully, choose the correct version, and remove the markers.

Practice Exercise

  1. In your git-practice folder from Lesson 3, run git switch -c feature/new-style.
  2. Make a change to index.html on this branch and commit it.
  3. Switch back to main with git switch main. Verify your change is NOT there.
  4. Merge the feature branch: git merge feature/new-style.
  5. Verify the change is now in main.
  6. Delete the feature branch: git branch -d feature/new-style.
  7. Run git log --oneline --graph to see the history.

Assignment

Simulate a merge conflict:

  1. Create a branch conflict-test.
  2. On conflict-test, change line 1 of index.html to something different.
  3. Switch to main and change the same line 1 to something else.
  4. Merge conflict-test into main. You should see a conflict.
  5. Open the file, resolve the conflict by choosing the version you want, remove the markers, stage, and commit.

Resolving conflicts calmly is a critical skill. The more you practise, the less scary they become.

Interview Questions

  • What is a Git branch? — A pointer to a specific commit. Creating a branch lets you work on a separate line of development without affecting other branches.
  • What is a merge conflict and how do you resolve one? — A conflict occurs when two branches change the same lines of a file. You resolve it by editing the file to remove the conflict markers and keep the correct code, then staging and committing.
  • What is the difference between merge and rebase? — Merge creates a merge commit preserving the branching history; rebase replays commits on top of another branch producing a linear history. Rebase should only be used on private branches.
  • What is a fast-forward merge? — When the target branch has no new commits since the feature branch split off, Git simply moves the pointer forward rather than creating a merge commit.