Skip to content
beginner Phase 5 · Git and Version Control

Branching and Merging

Create branches, switch contexts, merge with fast-forward and three-way strategies, and resolve merge conflicts.

1h
0 problems
Topic Progress 0%

Branch Operations

Branch Operations

Creating and Switching Branches

# List branches
git branch              # Local branches
git branch -r           # Remote branches
git branch -a           # All branches (local + remote)
git branch -v           # Last commit on each branch

# Create a new branch
git branch feature/auth

# Create and switch
git checkout -b feature/auth
git switch -c feature/auth     # Modern Git (2.23+)

# Switch to existing branch
git checkout main
git switch main

# Create branch from specific commit
git branch hotfix/bugfix abc1234

# Rename branch
git branch -m old-name new-name

# Delete branch
git branch -d feature/auth      # Safe delete (only if merged)
git branch -D feature/auth      # Force delete

# Delete remote branch
git push origin --delete feature/auth
git push origin :feature/auth   # Same thing

# See merged branches
git branch --merged
git branch --merged main        # Merged into main

# See unmerged branches
git branch --no-merged

Tracking Remote Branches

# Set upstream
git push -u origin feature/auth

# See which branch tracks what
git branch -vv

# Change tracking
git branch --set-upstream-to=origin/main main

# Prune stale remote branches
git fetch --prune
git remote prune origin

Merging

Merging

Fast-Forward Merge

When the target branch has no new commits since you branched off:

git checkout feature/auth
git merge main
# Just moves the pointer forward — clean history

# Fast-forward only
git merge --ff-only main

# No fast-forward (always create a merge commit)
git merge --no-ff main -m "Merge main into feature/auth"

Three-Way Merge

When both branches have diverged:

git checkout main
git merge feature/auth
# Creates a merge commit that combines both histories

# Example merge commit message:
# Merge branch 'feature/auth' into main
#
# * Add JWT validation
# * Implement login endpoint
# * Add password hashing

Squash Merge

Combines all commits from a branch into one:

git checkout main
git merge --squash feature/auth
git commit -m "Add complete user authentication module"

# This takes all changes from feature/auth,
# stages them as one commit, keeping history clean

Merge Strategies

# Recursive (default) — handles multiple merge bases
git merge -s recursive feature

# Ours — keep our version of conflicts
git merge -s ours feature

# Octopus — merge multiple branches at once
git merge branch1 branch2 branch3

Rebasing

Rebasing

Basic Rebase

# Move feature branch commits on top of main
git checkout feature/auth
git rebase main

# This rewrites history — commits get new hashes
# Result: linear history (no merge commits)

Interactive Rebase

# Rebase last 3 commits
git rebase -i HEAD~3

# Editor opens with:
pick abc1234 Add login endpoint
pick def5678 Fix typo in login
pick ghi9012 Add tests for login

# Commands:
# pick   = keep commit as-is
# reword = keep commit, edit message
# squash = combine with previous commit
# fixup  = combine, discard this commit's message
# drop   = remove commit entirely

# Example: squash fix typo into login endpoint
pick abc1234 Add login endpoint
squash def5678 Fix typo in login
pick ghi9012 Add tests for login

# This creates:
# abc1234 Add login endpoint (with typo fixed)
# ghi9012 Add tests for login

Rebase vs Merge

# Merge: preserves history, creates merge commits
git checkout main
git merge feature     # Creates merge commit

# Result:
# * Merge branch 'feature' (merge commit)
# |\
# | * Add feature B
# | * Add feature A
# *|
# * Initial commit

# Rebase: rewrites history, linear
git checkout feature
git rebase main

# Result:
# * Add feature B
# * Add feature A
# * Initial commit

# Rule of thumb:
# - Rebase local/private branches (not pushed)
# - Merge public/shared branches (don't rewrite history)

Handling Conflicts During Rebase

git rebase main
# CONFLICT in src/app.js

# 1. Edit the file to resolve conflicts
# 2. Stage the resolved file
git add src/app.js

# 3. Continue rebase
git rebase --continue

# 4. If you want to abort
git rebase --abort

# Skip a conflicting commit
git rebase --skip

Stashing and Worktrees

Stashing and Worktrees

Git Stash

# Stash current changes
git stash
git stash push -m "WIP: auth feature"

# Stash including untracked files
git stash -u
git stash --include-untracked

# List stashes
git stash list
# stash@{0}: On feature/auth: WIP: auth feature
# stash@{0}: On main: WIP: hotfix work

# Apply stash (keep in stash list)
git stash apply
git stash apply stash@{1}    # Apply specific stash

# Apply and remove
git stash pop
git stash pop stash@{1}

# Drop a stash
git stash drop stash@{0}

# Clear all stashes
git stash clear

# Show stash diff
git stash show -p
git stash show -p stash@{0}

# Create branch from stash
git stash branch feature-from-stash
git stash branch feature-from-stash stash@{0}

Git Worktree

Worktrees let you check out multiple branches simultaneously in separate directories:

# Create a worktree for a hotfix
git worktree add ../hotfix-branch hotfix/bugfix

# Work in the hotfix directory
cd ../hotfix-branch
# Make fixes, commit

# Return to main worktree
cd ../repo

# List worktrees
git worktree list

# Remove worktree
git worktree remove ../hotfix-branch

# Prune stale worktree references
git worktree prune

Practical Stash Scenarios

# Quick context switch: stash, switch, unstash
git stash push -m "Half-done feature"
git checkout main
# Do urgent hotfix
git checkout feature
git stash pop

# Stash only specific files
git stash push -m "Stash config changes" -- config.js .env

# Apply stash without removing
git stash apply stash@{0}
# If conflicts, fix them, then:
git stash drop stash@{0}

# Stash with message for organization
git stash push -m "[BUG] Fix in progress: memory leak"
git stash push -m "[FEATURE] WIP: new endpoint"
git stash list
# Shows clear labels for each stash

Git Workflows

Git Workflows

GitHub Flow (Simple)

Best for: small teams, continuous deployment

1. Pull latest main
git checkout main
git pull origin main

2. Create feature branch
git checkout -b feature/new-feature

3. Make changes, commit often
git add .
git commit -m "Add new feature part 1"
git commit -m "Add new feature part 2"

4. Push and create PR
git push -u origin feature/new-feature
# Create PR on GitHub

5. Code review, address feedback

6. Merge PR (merge button on GitHub)

7. Delete feature branch
git checkout main
git pull
git branch -d feature/new-feature

Gitflow (Structured)

Best for: scheduled releases, multiple versions

Branches:
- main:       production code
- develop:    integration branch
- feature/*:  new features
- release/*:  release preparation
- hotfix/*:   production fixes

# Start a feature
git checkout develop
git pull
git checkout -b feature/user-auth
# ... work ...
git checkout develop
git merge --no-ff feature/user-auth
git push origin develop

# Start a release
git checkout develop
git checkout -b release/1.0.0
git commit -m "Bump version to 1.0.0"
git checkout main
git merge --no-ff release/1.0.0
git tag -a v1.0.0 -m "Release 1.0.0"
git checkout develop
git merge --no-ff release/1.0.0

# Hotfix
git checkout main
git checkout -b hotfix/critical-bug
# ... fix ...
git checkout main
git merge --no-ff hotfix/critical-bug
git tag -a v1.0.1
git checkout develop
git merge --no-ff hotfix/critical-bug

Trunk-Based Development

Best for: high-performing teams, feature flags

1. Short-lived branches (hours, not days)
git checkout -b my-feature
# Quick changes, quick PR

2. Merge to main daily or more often

3. Use feature flags for incomplete features
if (featureFlags.enabled('new-auth')) {
    // new code
}

4. Never commit directly to main
git checkout -b fix/tiny-bug
# Commit, push, PR, merge