Understanding Git Merge Strategies: Merge, Rebase, Squash, and the Role of Staging Branches
Adam C. |

When working in a Git-based development team, especially in real-world projects, understanding how to manage branches and history is essential. This post explains the practical use of merge, rebase, and squash, as well as how to use demo or staging branches for safer and more flexible workflows.

Photo by Lance Grandahl on Unsplash

Merge, Rebase, and Squash: What's the Difference?

1. Merge

A git merge preserves full commit history by combining branches using a new merge commit. This creates a non-linear history with visible branch structure.

Example:

*   Merge branch 'feature/login'
|\
| * Add login UI
| * Hook up auth
* | Update README
|/
* Initial commit
  • ✅ Preserves all commits
  • ✅ Safe for shared branches
  • ❌ Creates a messier history

2. Rebase

git rebase moves your feature branch commits on top of the latest main, effectively rewriting history to make it look like your work was created linearly.

Example:

* Add login UI
* Hook up auth
* Update README
* Initial commit
  • ✅ Linear, clean history
  • ✅ Great for solo or short-lived branches
  • ❌ Rewrites commit hashes — dangerous on shared branches
  • ✅ Still preserves each individual commit

3. Squash

Squashing combines all your commits into a single one during merge (e.g. GitHub's "Squash and merge").

Example:

* Add login feature (squashed)
* Update README
* Initial commit
  • ✅ Very clean history (1 commit per feature)
  • ❌ Original commits are lost
  • ✅ Ideal for small PRs or open source contributions

Resolving Conflicts: Merge vs Rebase

When main has moved ahead and your feature branch is behind, you must resolve conflicts before merging.

🔁 Option 1: Merge main into your feature branch

git checkout feature/login
git merge origin/main

✅ Safe, preserves history
❌ Will create a merge commit

🔁 Option 2: Rebase your feature onto main

git checkout feature/login
git rebase origin/main

✅ Cleaner history
⚠️ Requires force-push if already pushed

Always resolve conflicts inside your feature branch, not on main.

What If You Resolve a Conflict Incorrectly?

Git has no way to know if your conflict resolution is logically wrong. If you accidentally delete part of a previously merged feature during rebase/merge, Git will accept it as valid. That’s why it's important to:

  • ✅ Carefully review changes (git diff / git log -p)
  • ✅ Run tests or QA before merging
  • ✅ Use code reviews to catch errors

The Role of a demo or staging Branch

Many teams use a branch like demo, staging, or dev as an intermediate testing environment.

✅ Why Use a Staging Branch

  • Combine multiple feature branches for QA or demos
  • Catch integration issues early
  • Test experimental features without affecting main

🔄 Typical Workflow

git checkout demo
git merge feature/login
git merge feature/auth

If a feature is later rejected, you can simply reset demo:

git checkout demo
git reset --hard origin/main

✅ Keeps main clean
✅ Allows testing in parallel

❌ Don't merge demo back into main

  • Doing so could bring in unreviewed or abandoned features
  • Always merge reviewed features directly into main from their respective branches

Summary

StrategyHistoryKeeps Commits?Clean?Safe on Shared Branch?
MergeNon-linear✅ Yes✅ Yes
RebaseLinear✅ Yes⚠️ Risky if shared
SquashLinear❌ No✅✅✅ Yes

When used wisely, these strategies give you the best of both worlds: clean, readable history and safe, flexible workflows.

If you're managing features across multiple environments, introducing a demo or staging branch lets you test without polluting your production history.

Use merge for safety, rebase for clarity, and squash for simplicity. Just be deliberate — and communicate with your team.