https://git-scm.com/book/en/v2
Git rebase is a powerful command that integrates changes from one branch into another by rewriting commit history. Unlike merging, which creates a new commit to join two branches, rebase moves or replays your commits to a new base commit, making it appear as though your work was started from a different point in the repository's history.
When you rebase, Git:
Critical caveat: Rebase creates entirely new commits with different SHA-1 hashes, even though the content may be identical. This means rebased commits are technically different objects in Git's history.
Rebase creates a straight line of commits without merge commits, making the project history easier to read and understand.
Frequent merges from main into feature branches create cluttered histories full of "Merge branch 'main' into feature" commits. Rebase avoids this noise.
A linear history makes it simpler to use tools like git log, git bisect, and code review interfaces to track down when changes were introduced.
Keep your feature branch up-to-date with the latest changes from main or develop without creating merge commits.
Before submitting a pull request, you can rebase your feature branch onto the latest main to ensure a clean, conflict-free integration.
Interactive rebase (git rebase -i) allows you to squash, reorder, edit, or delete commits before sharing your work.
Imagine you're working on a feature branch while others are updating main:
Before Rebase:
C---D feature
/
A---B---E---F main
Your feature branch (C, D) diverged from main at commit B. Meanwhile, main has moved forward with commits E and F.
After git rebase main:
C'---D' feature
/
A---B---E---F main
Git has:
C and D temporarilyF (the tip of main)C and D as new commits C' and D'Important: C' and D' have different commit hashes than C and D, even if their content is identical.
Keep your feature branch current with the latest main:
# On your feature branch
git checkout feature
git rebase main
What happens:
feature and mainmainClean up your commit history before merging:
git rebase -i HEAD~3 # Rebase last 3 commits
This opens an editor showing:
pick abc1234 Add user authentication
pick def5678 Fix typo in login form
pick ghi9012 Update authentication tests
Available commands:
pick (p) - Keep commit as-isreword (r) - Keep commit, but edit messagesquash (s) - Combine with previous commitfixup (f) - Like squash, but discard commit messageedit (e) - Pause to amend commitdrop (d) - Remove commit entirelyreorder - Simply rearrange linesExample - Squashing commits:
pick abc1234 Add user authentication
squash def5678 Fix typo in login form
squash ghi9012 Update authentication tests
This combines all three into a single commit.
If conflicts occur during rebase:
# Git pauses and shows conflicts
# Edit files to resolve conflicts
git add <resolved-files>
git rebase --continue
# Or skip this commit
git rebase --skip
# Or abort entirely
git rebase --abort
C---D feature
/ \
A---B---E---F---G main
^
merge commit
Result: History shows exactly what happened, but can become cluttered with merge commits.
C'---D' feature
/
A---B---E---F main
Result: Clean linear history, but rewrites commits (changes hashes).
Never rebase commits that have been pushed to a public/shared repository and that other people may have based work on.
Why? Because rebase creates new commit hashes, anyone who has pulled your original commits will have divergent histories, leading to confusion and messy merges.
✅ Local commits not yet pushed
✅ Cleaning up your own feature branch
✅ Updating your branch with latest main before creating a PR
✅ Your feature branch that only you work on
❌ Commits already pushed to shared branches
❌ The main or master branch
❌ Public release branches
❌ Branches where others are actively committing
git rebase --onto main server client
Takes commits from client that aren't in server and replays them onto main.
git rebase -p main # or --preserve-merges (deprecated)
git rebase --rebase-merges main # newer syntax
# Create fixup commit
git commit --fixup=abc1234
# Later, automatically squash it
git rebase -i --autosquash main
git checkout feature
git fetch origin
git rebase origin/main
git push --force-with-lease
git rebase -i HEAD~5 # Clean last 5 commits
# Squash, reword, reorder as needed
git rebase -i HEAD~1
# Mark commit as 'edit'
git reset HEAD^
# Make multiple smaller commits
git rebase --continue
# Find the commit before rebase
git reflog
# Reset to that point
git reset --hard HEAD@{5}
After rebasing pushed commits (only on your own branches):
git push --force-with-lease
This prevents overwriting changes if someone else has pushed to the branch.
--force-with-lease instead of --force when force-pushing# Basic rebase
git rebase <branch>
# Interactive rebase
git rebase -i <commit>
# Continue after resolving conflicts
git rebase --continue
# Skip current commit
git rebase --skip
# Abort rebase
git rebase --abort
# Rebase onto different base
git rebase --onto <newbase> <oldbase> <branch>
# Preserve merge commits
git rebase --rebase-merges <branch>
Git rebase is a powerful tool for maintaining clean, linear project histories. Used correctly, it makes collaboration smoother and code history more understandable. However, it requires discipline and adherence to the golden rule: never rebase shared commits. When in doubt, use merge for public branches and save rebase for your local, private work.