Rebasing
Rebasing is a powerful Git feature that allows you to rewrite commit history by moving or combining commits. In this lesson, we'll explore what rebasing is, when to use it, and how it differs from merging.
What is Rebasing?
Rebasing is the process of moving or combining a sequence of commits to a new base commit. Unlike merging, which creates a new commit with two parents, rebasing rewrites the project history by creating new commits for each commit in the original branch.
Key Concept: Rebasing changes the commit history by rewriting it, making it appear as if you created your commits from a different starting point.
Basic Rebase Command
The basic syntax for rebasing is:
# Rebase current branch onto another branch
git rebase <base-branch>
# Example: Rebase feature branch onto main
git checkout feature-branch
git rebase main
How Rebasing Works
Here's what happens during a rebase:
1. Git finds the common ancestor of current branch and target branch
2. Git saves all commits made since the common ancestor
3. Git resets the current branch to the target branch
4. Git applies each saved commit one by one on top of target branch
5. Each commit gets a new SHA hash (new commit ID)
Tip: Think of rebasing as "replaying" your commits on top of a different starting point, creating a linear history.
Visual Example: Rebase vs Merge
Before:
C3 (feature)
/
C1--C2 (main)
After Merge:
C3 (feature)
/ \
C1--C2--C4 (main) ← merge commit
After Rebase:
C1--C2--C3' (feature) ← rebased commit
(main)
Interactive Rebase
Interactive rebase is one of Git's most powerful features, allowing you to edit, reorder, squash, or delete commits:
# Start interactive rebase for last 3 commits
git rebase -i HEAD~3
# Interactive rebase onto a branch
git rebase -i main
This opens an editor with options:
pick abc1234 Add login feature
pick def5678 Fix typo in login
pick ghi9012 Update documentation
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit message
# e, edit = use commit, but stop for amending
# s, squash = meld into previous commit
# f, fixup = like squash, but discard message
# d, drop = remove commit
Squashing Commits
Squashing combines multiple commits into one, creating a cleaner history:
# Change in interactive rebase editor:
pick abc1234 Add login feature
squash def5678 Fix typo in login
squash ghi9012 Update documentation
# Results in one commit with combined changes
Use Case: Squash commits before merging a feature branch to keep the main branch history clean and focused on complete features rather than incremental changes.
Rebase vs Merge: When to Use Each
Use REBASE when:
✓ Working on a local feature branch
✓ Want to maintain a linear project history
✓ Updating feature branch with latest main changes
✓ Cleaning up commits before pushing
✓ Working alone on a branch
Use MERGE when:
✓ Integrating completed features into main branch
✓ Working on public/shared branches
✓ Want to preserve exact history of changes
✓ Multiple people working on same branch
✓ Want to see when features were integrated
The Golden Rule of Rebasing
Critical Rule: Never rebase commits that have been pushed to a public repository and that others may have based work on. Rebasing rewrites history, which can cause serious issues for collaborators.
Safe rebasing practices:
✓ Rebase local commits that haven't been pushed
✓ Rebase your own feature branches
✓ Rebase before creating a pull request
✗ Never rebase the main/master branch
✗ Never rebase commits others are working on
✗ Never rebase public release branches
Resolving Rebase Conflicts
Conflicts during rebase are resolved one commit at a time:
# If conflict occurs during rebase:
# 1. Fix conflicts in affected files
git status # See conflicted files
# 2. Stage resolved files
git add <resolved-files>
# 3. Continue rebase
git rebase --continue
# Or abort if needed
git rebase --abort
Tip: During a rebase, you may need to resolve the same conflict multiple times if it appears in different commits. Be patient and resolve each carefully.
Practical Rebase Workflow
Here's a common workflow for keeping a feature branch up to date:
# You're working on feature-branch
git checkout feature-branch
# Fetch latest changes from remote
git fetch origin
# Rebase your branch onto latest main
git rebase origin/main
# If conflicts occur, resolve and continue
# Once complete, force push (only if previously pushed)
git push --force-with-lease origin feature-branch
Rewriting Commit Messages
Use reword to change commit messages without changing content:
# Start interactive rebase
git rebase -i HEAD~3
# In editor, change pick to reword:
reword abc1234 Add login feature
pick def5678 Fix typo
pick ghi9012 Update docs
# Git will pause at each reword commit
# Edit the message and save
Editing Past Commits
Use edit to modify the content of past commits:
# Start interactive rebase
git rebase -i HEAD~3
# Change pick to edit for commits to modify
edit abc1234 Add login feature
pick def5678 Fix typo
# Git stops at the edit commit
# Make your changes
git add <files>
git commit --amend
git rebase --continue
Dropping Commits
Remove unwanted commits from history:
# In interactive rebase editor:
pick abc1234 Add feature
drop def5678 Accidentally committed secrets
pick ghi9012 Update docs
# Or simply delete the line
Security Note: If you accidentally committed secrets, dropping the commit isn't enough - the secrets are still in Git history. You need to use git filter-branch or BFG Repo-Cleaner to completely remove them.
Rebase Onto a Different Branch
You can rebase onto any branch or commit:
# Rebase current branch onto develop
git rebase develop
# Rebase feature-a onto feature-b
git checkout feature-a
git rebase feature-b
# Rebase onto a specific commit
git rebase abc1234
Abort and Skip Options
# Abort rebase and return to original state
git rebase --abort
# Skip the current commit (if causing issues)
git rebase --skip
# Continue after resolving conflicts
git rebase --continue
Practice Exercise:
Scenario: You have a feature branch with 3 messy commits that you want to clean up before merging.
# Create a practice repo
git init rebase-practice
cd rebase-practice
# Create some commits
echo "Feature v1" > feature.txt
git add feature.txt
git commit -m "Add feature"
echo "Feature v2" >> feature.txt
git commit -am "Fix typo"
echo "Feature v3" >> feature.txt
git commit -am "Another fix"
# Now squash the 3 commits into one
git rebase -i HEAD~3
# In editor, change to:
# pick (first commit)
# squash (second commit)
# squash (third commit)
# Save and edit the combined commit message
# View the result
git log --oneline
Challenge: Practice splitting a commit by using 'edit' command, then git reset HEAD^, and making two separate commits.
Common Rebase Pitfalls
Pitfall 1: Rebasing pushed commits
→ Solution: Only rebase local commits
Pitfall 2: Losing commits during rebase
→ Solution: Use git reflog to recover
Pitfall 3: Complex merge conflicts
→ Solution: Abort and use merge instead
Pitfall 4: Forgetting to force-push after rebase
→ Solution: Use --force-with-lease for safety
Advanced: Autosquash
Git can automatically squash fixup commits:
# Create a fixup commit for a previous commit
git commit --fixup abc1234
# Later, automatically squash all fixups
git rebase -i --autosquash main
Summary
In this lesson, you learned:
- Rebasing moves commits to a new base, rewriting history
- Interactive rebase allows editing, squashing, and reordering commits
- Use rebase for local branches, merge for public branches
- Never rebase commits that others have based work on
- Resolve rebase conflicts one commit at a time
- Squashing creates cleaner, more focused commit history
- Use --force-with-lease when pushing rebased branches
Next Up: In the next lesson, we'll explore remote repositories and learn how to work with them effectively!