Fatskills
Practice. Master. Repeat.
Study Guide: TECH **Git & GitHub Merge Strategies: Squash, Rebase, and Merge Commits**
Source: https://www.fatskills.com/web-development/chapter/tech-git-github-merge-strategies-squash-rebase-and-merge-commits

TECH **Git & GitHub Merge Strategies: Squash, Rebase, and Merge Commits**

By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.

⏱️ ~6 min read

Git & GitHub Merge Strategies: Squash, Rebase, and Merge Commits

A Hyper-Practical Guide for Engineers


1. What This Is & Why It Matters

You’re working on a feature branch with 10 small commits—typo fixes, debug logs, and minor refactors. When you merge into main, do you: - Keep all 10 commits (cluttering history)? - Squash them into one clean commit (losing granularity)? - Rebase interactively to rewrite history (risking conflicts)?

Merge strategies determine how your work integrates into the main codebase. Choose wrong, and you’ll: - Pollute git log with noise, making debugging harder.
- Break bisect (Git’s binary search for bugs) if commits aren’t atomic.
- Cause merge conflicts that waste hours to resolve.
- Violate team conventions, forcing rework before PR approval.

Real-world scenario:
You’re a DevOps engineer maintaining a microservice. A teammate opens a PR with 20 "WIP" commits. The CI pipeline fails on the 15th commit, but the PR is approved. If you merge as-is, main now contains broken code. Squash merging would collapse all commits into one, ensuring main only gets working code.


2. Core Concepts & Components


1. Merge Commit (Default Strategy)

  • Definition: Creates a new commit that ties two branches together, preserving all commit history.
  • Production insight: Use when you want a full audit trail (e.g., regulated industries like finance/healthcare). ⚠️ Can clutter history with "Merge branch 'feature-x' into 'main'" commits.

2. Squash Merge

  • Definition: Combines all commits from a branch into a single new commit on the target branch.
  • Production insight: Ideal for feature branches with many small commits. Keeps main clean but loses granular history (e.g., "Fix typo" commits disappear). Use for short-lived branches.

3. Rebase Merge

  • Definition: Replays commits from your branch on top of the target branch, then does a fast-forward merge (no merge commit).
  • Production insight: Creates a linear history but rewrites commit hashes. Never rebase shared branches (e.g., main)—it breaks others’ work. Best for local branches before opening a PR.

4. Fast-Forward Merge

  • Definition: Moves the branch pointer forward if no divergent commits exist (no merge commit created).
  • Production insight: Git’s default behavior when possible. Keeps history linear but only works if the target branch hasn’t changed since you branched.

5. Interactive Rebase (git rebase -i)

  • Definition: Lets you edit, squash, drop, or reorder commits before merging.
  • Production insight: Use to clean up local commits before pushing. ⚠️ Never rebase public commits (already pushed to remote).

6. GitHub Merge Queue

  • Definition: Automatically tests and merges PRs in order, preventing merge conflicts.
  • Production insight: Enabled in GitHub repo settings. Reduces "merge hell" in high-velocity teams.


3. Step-by-Step Hands-On


Prerequisites

  • Git installed (git --version).
  • A GitHub repo (or local Git repo).
  • A feature branch with multiple commits.


Task: Squash Merge a PR on GitHub

Goal: Collapse 5 commits into 1 before merging to main.


  1. Create a feature branch and make commits:
    bash
    git checkout -b feature/login
    echo "Add login button" > login.html
    git add login.html
    git commit -m "Add login button"
    echo "Fix button color" >> login.html
    git commit -am "Fix button color"
    echo "Add debug log" >> login.html
    git commit -am "Add debug log"
    echo "Remove debug log" >> login.html
    git commit -am "Remove debug log"
    echo "Update docs" >> README.md
    git commit -am "Update docs"
    git push origin feature/login

  2. Open a PR on GitHub:

  3. Go to your repo → Pull RequestsNew Pull Request.
  4. Select feature/loginmain.
  5. Click Create Pull Request.

  6. Squash merge via GitHub UI:

  7. In the PR, click the dropdown next to Merge pull request.
  8. Select Squash and merge.
  9. Edit the commit message (e.g., "Add login feature").
  10. Click Squash and merge.

  11. Verify:
    bash
    git checkout main
    git pull
    git log --oneline -5

    Expected output:
    abc1234 (HEAD -> main) Add login feature
    def5678 Previous main commit


Task: Rebase Merge Locally

Goal: Rebase a feature branch onto main before merging.


  1. Update main and rebase:
    bash
    git checkout main
    git pull
    git checkout feature/login
    git rebase main
  2. If conflicts occur, resolve them, then:
    bash
    git add .
    git rebase --continue

  3. Fast-forward merge:
    bash
    git checkout main
    git merge feature/login # Fast-forwards if no conflicts

  4. Verify:
    bash
    git log --oneline --graph

    Expected output: Linear history with no merge commits.


Task: Interactive Rebase to Clean Up Commits

Goal: Squash "Fix typo" commits before pushing.


  1. Start interactive rebase:
    bash
    git rebase -i HEAD~4 # Edit last 4 commits

  2. Edit the rebase todo list:
    pick abc1234 Add login button
    squash def5678 Fix button color
    squash ghi7890 Add debug log
    squash jkl0123 Remove debug log
    pick mno4567 Update docs

  3. Save and exit.

  4. Edit the new commit message:
    ```
    Add login feature with button

  5. Includes button color fix

  6. Removes debug logs
    ```

  7. Push changes (force push if already pushed):
    bash
    git push origin feature/login --force


4. ? Production-Ready Best Practices


Team Workflow

  • Squash merge: Use for feature branches with many small commits.
  • Rebase merge: Use for local branches to keep history linear.
  • Merge commit: Use for long-lived branches (e.g., develop) to preserve context.

GitHub Settings

  • Require linear history: Enable in repo settings → Merge buttonRequire linear history (forces rebase merges).
  • Default to squash merge: Set in repo settings → Merge buttonDefault to squash merging.

Commit Hygiene

  • Atomic commits: Each commit should do one thing (e.g., "Add login button" vs. "Add login button and fix typo").
  • Conventional commits: Use prefixes like feat:, fix:, docs: for clarity.

Conflict Resolution

  • Always pull latest main before merging:
    bash git checkout main git pull git checkout feature/login git rebase main
  • Use git rerere (Reuse Recorded Resolution) to automate conflict fixes: bash git config --global rerere.enabled true


5. ⚠️ Common Mistakes & Traps

Mistake Symptom Fix/Prevention
Rebasing public commits Teammates get errors like non-fast-forward Never rebase pushed commits. Use git pull --rebase instead of git pull.
Squashing too aggressively Loses useful history (e.g., "Fix security bug") Squash only "noise" commits (typos, debug logs).
Merge commits in linear workflows git log becomes a mess of "Merge branch X" Use rebase merges or squash merges.
Not pulling latest main before merging Merge conflicts or overwritten changes Always git pull before merging.
Force-pushing to shared branches Breaks others’ work Only force-push to private branches.


6. ? Exam/Certification Focus


Typical Questions

  1. Scenario: "Your team uses squash merges. A PR has 10 commits. What happens when merged?"
  2. Answer: All commits are combined into one. History is cleaner but loses granularity.

  3. Scenario: "You rebase a branch and push. Teammates complain about conflicts. Why?"

  4. Answer: Rebasing rewrites commit hashes. Teammates must git pull --rebase to sync.

  5. Trick Question: "Which merge strategy preserves all commit history?"

  6. Answer: Merge commit (not squash or rebase).

Key Distinctions

Strategy History Merge Commit? Use Case
Merge commit Preserves all Yes Long-lived branches
Squash merge Collapses all No Feature branches with noise
Rebase merge Linear No Local branches before PR


7. ? Hands-On Challenge

Challenge:
You have a branch feature/payment with 3 commits: 1. Add payment form 2. Fix typo in form 3. Add validation

Squash the last two commits into the first one using interactive rebase.

Solution:


git rebase -i HEAD~3
# In the editor, mark commits 2 and 3 as "squash"
git push origin feature/payment --force

Why it works: Interactive rebase lets you edit commit history before pushing.


8. ? Rapid-Reference Crib Sheet

Command/Action Purpose Example
git merge --no-ff Force merge commit (even if fast-forward) git merge --no-ff feature/login
git rebase main Rebase current branch onto main git checkout feature/login && git rebase main
git rebase -i HEAD~3 Interactive rebase last 3 commits squash commits 2 and 3
git merge --squash feature/login Squash merge locally (no commit) git merge --squash feature/login && git commit
git push --force-with-lease Safer force push (checks remote refs) git push origin feature/login --force-with-lease
GitHub UI Squash merge a PR PR → Dropdown → Squash and merge
GitHub Settings Require linear history Repo → Settings → Merge button → Require linear history

⚠️ Never git push --force to main or shared branches!


9. ? Where to Go Next

  1. GitHub Docs: About Merge Methods
  2. Git Rebase Interactive Guide
  3. Atomic Commits Best Practices
  4. GitHub Merge Queue


ADVERTISEMENT