The Difference Between Merge and Rebase
Both git merge and git rebase are designed to integrate changes from one branch into another. However, they do it in very different ways.
Merging preserves history exactly as it happened. It brings two lines of history together in a “merge commit”.
Rebasing rewrites history. It takes the commits from your branch and “replays” them on top of another branch.
The #FFD700en Rule of Rebasing
Never rebase public history.
If you rebase commits that you have already pushed and others have pulled, you are rewriting history that they depend on. This will cause chaos. Only rebase local commits that you haven’t shared yet.
Interactive Rebase
The most powerful form of rebasing is “Interactive Rebase” (-i). This allows you to edit, delete, squash, and reorder commits as they are being replayed.
git rebase -i HEAD~3
This opens an editor with a list of the last 3 commits:
pick a1b2c3d Fix login bug
pick 4e5f6g7 Add unit tests
pick 7h8i9j0 Update documentation
You can change the word pick to other commands:
- reword: Keep the commit, but edit the message.
- edit: Stop at this commit to make changes to files.
- squash: Combine this commit with the previous one.
- fixup: Combine with previous, but discard this log message.
- drop: Remove the commit entirely.
Squashing Commits
Squashing is a common pattern to clean up a messy history before merging. If you have 10 commits saying “WIP”, “Typo”, “Fixing bug”, you can squash them into one clean “Implement Feature X” commit.
Example:
pick a1b2c3d Implement Feature X
squash 4e5f6g7 WIP
squash 7h8i9j0 Fix typo
This merges the 3 commits into one, prompting you to write a new commit message for the combined result.
Rebase vs. Merge Workflows
The Merge Workflow
- Pros: Preserves complete history, non-destructive.
- Cons: History can become cluttered with “Merge branch…” commits and complex graphs.
The Rebase Workflow
- Pros: Creates a linear history (straight line), easier to read and bisect.
- Cons: Rewrites history, potential for lost data if not careful, conflicts can be harder to resolve (you resolve them commit by commit).
Pulling with Rebase
By default, git pull performs a merge. If you want to keep your local history linear on top of the remote changes, you can pull with rebase.
git pull --rebase
You can set this globally:
git config --global pull.rebase true
Autosquashing
If you know you want to fix up a previous commit while you are making the change, you can use autosquash.
- Make your change.
- Commit with
--fixup:git commit --fixup <commit-hash-to-fix> - Run rebase with autosquash:
git rebase -i --autosquash HEAD~5
Git will automatically rearrange the TODO list to pair the fixup commit with its target.
Why should you never rebase public commits?
Interactive Rebase
# You want to interactively rebase the last 5 commits to cleanup history. git rebase HEAD~5