Git Rebasing

Git Rebasing

Git rebase is a powerful tool for maintaining a clean, linear project history. Unlike merging, which creates merge commits, rebasing rewrites history by moving commits to a new base. This tutorial covers the fundamentals of rebasing, when to use it, and best practices to avoid common pitfalls.

What is Rebasing?

Rebasing is the process of moving or combining a sequence of commits to a new base commit. Instead of creating a merge commit like git merge does, git rebase rewrites the project history by creating new commits for each commit in the original branch.

Basic Rebasing

Rebase onto Another Branch

# Switch to the branch you want to rebase
git checkout feature-branch

# Rebase onto main branch
git rebase main

This moves all commits from feature-branch that aren’t in main to the tip of main.

Interactive Rebasing

Interactive rebase allows you to modify commits during the rebase process.

# Start interactive rebase for the last 3 commits
git rebase -i HEAD~3

This opens an editor with options like:

  • pick: Keep the commit as is
  • reword: Change the commit message
  • edit: Amend the commit
  • squash: Combine with previous commit
  • fixup: Combine without keeping the message
  • drop: Remove the commit

When to Use Rebase

Keeping Feature Branches Updated

# On your feature branch
git checkout feature/login
git rebase main

# Resolve any conflicts, then
git push --force-with-lease

Cleaning Up Commit History

# Squash multiple small commits into one
git rebase -i HEAD~5
# In editor: change 'pick' to 'squash' for commits 2-5

Incorporating Upstream Changes

# Update your local main branch
git checkout main
git pull origin main

# Rebase your feature branch
git checkout feature/new-feature
git rebase main

Rebasing vs Merging

AspectMergeRebase
HistoryPreserves all historyCreates linear history
CommitsCreates merge commitRewrites commits
ConflictsResolved onceMay resolve multiple times
SafetySafer for shared branchesRiskier for shared branches

Handling Conflicts

Conflicts during rebase are resolved similarly to merge conflicts, but for each commit.

# After conflict occurs
git status  # See conflicted files
# Edit files to resolve conflicts
git add <resolved-files>
git rebase --continue

# Or abort if too messy
git rebase --abort

Advanced Rebasing

Rebasing onto a Specific Commit

# Rebase feature branch onto a specific commit
git rebase abc123 feature-branch

Autosquash for Fixup Commits

# Create a fixup commit
git commit --fixup HEAD~2

# Apply it automatically
git rebase -i --autosquash HEAD~3

Preserving Merge Commits

# Rebase while keeping merge commits
git rebase --preserve-merges main

Best Practices

1. Don’t Rebase Public History

Never rebase commits that have been pushed to a shared repository.

# ✅ Good: Rebase local commits
git checkout feature/my-work
git rebase main
git push --force-with-lease origin feature/my-work

# ❌ Bad: Rebase shared branch
git checkout main
git rebase feature/some-branch  # Don't do this!

2. Use Force with Lease

When force pushing after rebase, use --force-with-lease instead of --force.

git push --force-with-lease origin feature-branch

3. Rebase Frequently

Keep your branches up to date by rebasing regularly.

# Daily workflow
git checkout feature/my-feature
git fetch origin
git rebase origin/main

4. Clean Commit History

Use interactive rebase to create meaningful commits.

# Before pushing, clean up your commits
git rebase -i origin/main

Common Scenarios

Fixing a Mistake in Recent Commits

# Amend the last commit
git commit --amend

# Or rebase to fix older commits
git rebase -i HEAD~3
# Change 'pick' to 'edit' for the commit to fix

Splitting a Large Commit

git rebase -i HEAD~2
# Change 'pick' to 'edit' for the large commit
git reset HEAD~1  # Uncommit but keep changes
git add -p  # Stage changes in parts
git commit -m "First part"
git commit -m "Second part"
git rebase --continue

Reordering Commits

git rebase -i HEAD~4
# Reorder the lines in the editor

Working with Remote Branches

Pulling with Rebase

# Instead of merge, rebase when pulling
git pull --rebase origin main

Rebasing a Branch with Remote Tracking

# Set up branch for rebase by default
git config branch.feature-branch.rebase true

# Or globally
git config pull.rebase true

Troubleshooting

Recovering from a Botched Rebase

# If rebase goes wrong, abort
git rebase --abort

# Or if you need to recover lost commits
git reflog
git reset --hard HEAD@{2}  # Go back 2 steps

Dealing with Empty Commits

# Sometimes rebase creates empty commits
git rebase -i HEAD~5
# Change empty commits to 'drop'

Complete Workflow Example

# Start a feature
git checkout -b feature/user-auth
# Make some commits...
git commit -m "Add login form"
git commit -m "Add validation"
git commit -m "Fix typo"

# Keep branch updated
git fetch origin
git rebase origin/main

# Clean up commits before PR
git rebase -i origin/main
# Squash related commits, fix messages

# Force push (since history changed)
git push --force-with-lease origin feature/user-auth

Summary

Rebasing is a powerful tool for maintaining clean Git history:

  • Use rebase for local branches and feature development
  • Use merge for integrating completed features into main branches
  • Never rebase commits that exist in shared repositories
  • Always use --force-with-lease when force pushing
  • Regular rebasing keeps branches current and reduces conflicts

Mastering rebase will help you maintain professional, clean Git repositories and collaborate more effectively with your team.


External Resources:

Related Tutorials:

  • Learn about Git branching and merging here to understand the alternatives to rebasing.
  • Check out how to ignore committed files here for managing what gets tracked in Git.
Last updated on