Git Rebase Guide: Merge vs Rebase Explained
This guide explains the difference between git merge and git rebase, why Pivot requires rebasing, and how to avoid common mistakes.
The Golden Rule
Never use git merge to update your feature branch. Always use git rebase.
Why This Matters: A Real Example
PR #936 showed 250+ commits when it should have shown ~50. Here's what happened:
The developer kept running git merge development into their feature branch. Each merge:
- Created a merge commit
- Pulled ALL commits from development into the feature branch
- Made the PR show hundreds of "new" commits
Merge vs Rebase: Visual Comparison
Starting Point
You create a feature branch from development:
Now development has new commits (D, E) that you need in your branch. You have two choices:
Option 1: Merge (WRONG)
git checkout feature
git merge development # DON'T DO THIS
Result:
Problems:
- Creates a merge commit in your branch
- Your branch now contains D, E from development
- PR will show D, E as "new" commits in your branch
- Violates linear history requirement
- PR will be blocked by GitHub
Option 2: Rebase (CORRECT)
git checkout feature
git rebase development # DO THIS
git push --force-with-lease
Result:
Benefits:
- No merge commit
- Your commits are replayed ON TOP of the latest development
- PR only shows YOUR commits
- Clean, linear history
- PR can be merged
Step-by-Step: How to Rebase
1. Make sure your local development is up to date
git checkout development
git pull origin development
2. Switch to your feature branch
git checkout my-feature
3. Rebase onto development
git rebase development
4. Resolve conflicts if any
If there are conflicts:
# Fix the conflicts in your editor
git add .
git rebase --continue
To abort if things go wrong:
git rebase --abort
5. Force push (required after rebase)
git push --force-with-lease
--force-with-lease is safer than --force because it fails if someone else pushed to your branch.
Common Mistakes and How to Fix Them
Mistake 1: "I already merged, now what?"
If you accidentally ran git merge development:
# Find the commit before the merge
git log --oneline
# Reset to before the merge
git reset --hard HEAD~1 # Or use the specific commit hash
# Now rebase instead
git rebase development
git push --force-with-lease
Mistake 2: "My branch has many merge commits"
If you have multiple merge commits accumulated:
# Find where your branch diverged from development
git merge-base development my-feature
# Reset to that point (keeping your changes)
git reset --soft <merge-base-hash>
# Create a fresh commit with all your changes
git commit -m "My feature work"
# Rebase onto latest development
git rebase development
git push --force-with-lease
Mistake 3: "I based my branch on another feature branch"
This is actually fine! But the parent branch must be merged first.
Example: You created payroll-introduction from feat/payroll-tips
Solution:
- Merge
feat/payroll-tipsintodevelopmentfirst (PR #795) - Then your PR will automatically show only your commits
- Or rebase
payroll-introductionontodevelopmentafter step 1
Rebase Workflow Cheat Sheet
Daily workflow
# Start of day: update your branch
git checkout development
git pull
git checkout my-feature
git rebase development
git push --force-with-lease
Before opening a PR
git checkout development
git pull
git checkout my-feature
git rebase development
# Fix any conflicts
git push --force-with-lease
# Now open PR
When PR has conflicts
git checkout development
git pull
git checkout my-feature
git rebase development
# Fix conflicts
git add .
git rebase --continue
git push --force-with-lease
Why Pivot Requires Linear History
Our branch protection rules enforce required_linear_history = true. This means:
- No merge commits allowed in PRs
- Cleaner git history - easy to read and understand
- Easier to bisect - find bugs with
git bisect - Simpler rollbacks - revert individual commits cleanly
Quick Reference
| Action | Command |
|---|---|
| Update feature branch | git rebase development |
| Push after rebase | git push --force-with-lease |
| Abort failed rebase | git rebase --abort |
| Continue after fixing conflicts | git rebase --continue |
| Skip a problematic commit | git rebase --skip |
| See rebase progress | git status |
Summary
| Merge | Rebase |
|---|---|
| Creates merge commits | No merge commits |
| Preserves exact history | Rewrites history (cleaner) |
| PRs show extra commits | PRs show only your commits |
| Blocked by our branch protection | Allowed |
git merge development | git rebase development |
git push | git push --force-with-lease |
Remember: When in doubt, rebase. If you mess up, git rebase --abort and start over.