
How to Use Git Rebase – A Beginner’s Guide
Git rebase is one of those Git commands that sparks heated debates in developer circles – some swear by it for maintaining clean commit histories, while others avoid it like the plague. Understanding how to use rebase effectively will help you streamline your development workflow, create linear project histories, and make your commits easier to review and understand. In this guide, we’ll walk through everything you need to know about Git rebase, from basic concepts to advanced techniques, complete with practical examples and troubleshooting tips.
How Git Rebase Works Under the Hood
Before diving into commands, let’s demystify what rebase actually does. Unlike a merge that creates a new commit combining two branches, rebase takes commits from one branch and replays them on top of another branch. Think of it as picking up a series of commits and moving them to a new starting point.
When you run a rebase, Git temporarily removes the commits you want to move, applies any commits from the target branch, then reapplies your commits one by one. This creates brand new commit objects with different SHA hashes, even though the changes might be identical.
Here’s the crucial part: rebase rewrites history. Each commit gets a new SHA hash because its parent commit has changed. This is why you should never rebase commits that have been pushed to a shared repository where others might have based work on them.
Basic Git Rebase Commands and Setup
Let’s start with the fundamental rebase operations. First, make sure you’re working with a clean repository:
git status
git stash # if you have uncommitted changes
The most common rebase scenario is updating your feature branch with the latest changes from main:
# Switch to your feature branch
git checkout feature-branch
# Rebase onto main
git rebase main
If you encounter conflicts during rebase, Git will pause and let you resolve them:
# Edit files to resolve conflicts
# After resolving conflicts:
git add .
git rebase --continue
# To abort the entire rebase:
git rebase --abort
# To skip a problematic commit:
git rebase --skip
For interactive rebasing, which gives you fine-grained control over individual commits:
# Interactive rebase for the last 3 commits
git rebase -i HEAD~3
# Interactive rebase from a specific commit
git rebase -i abc123
Interactive Rebase: Your Swiss Army Knife
Interactive rebase is where the real power lies. When you run git rebase -i
, Git opens your default editor with a list of commits and actions:
pick f7f3f6d Add authentication module
pick 310154e Fix typo in login form
pick a5f4a0d Update documentation
# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
Here are the most useful interactive rebase operations:
- Squashing commits: Change “pick” to “squash” or “s” to combine commits
- Rewording messages: Use “reword” or “r” to edit commit messages
- Reordering commits: Simply move the lines around
- Dropping commits: Change “pick” to “drop” or delete the line entirely
- Editing commits: Use “edit” to pause and make changes to a commit
Real-World Use Cases and Examples
Let’s look at some practical scenarios where rebase shines:
Scenario 1: Cleaning Up Your Feature Branch
You’ve been working on a feature and have commits like “WIP”, “Fix bug”, “Another fix”. Before merging, clean this up:
git log --oneline
# a1b2c3d Another fix
# d4e5f6g Fix bug
# h7i8j9k WIP: Add user validation
# k0l1m2n Add user registration form
git rebase -i HEAD~4
# Squash the fixes into meaningful commits
Scenario 2: Keeping Feature Branch Updated
Your feature branch is behind main. Instead of merge commits, use rebase for a linear history:
git checkout feature-auth
git rebase main
# Now your feature branch includes all main changes
# and your commits appear after the latest main commit
Scenario 3: Splitting a Large Commit
You accidentally included unrelated changes in a single commit:
git rebase -i HEAD~1
# Change "pick" to "edit" for the commit to split
# When rebase pauses:
git reset HEAD~1 # Unstage the commit
git add file1.py # Stage related changes
git commit -m "Add user validation"
git add file2.py # Stage other changes
git commit -m "Update login UI"
git rebase --continue
Git Rebase vs Git Merge: When to Use Each
Aspect | Git Rebase | Git Merge |
---|---|---|
History | Linear, clean history | Preserves actual development timeline |
Commit SHA | Creates new commit objects | Preserves original commits |
Collaboration | Never rebase shared commits | Safe for shared branches |
Conflict Resolution | Resolve conflicts per commit | Resolve all conflicts at once |
Use Case | Feature branches, cleanup | Integration, releases |
Complexity | Higher learning curve | Simpler to understand |
Advanced Rebase Techniques
Rebase with Autosquash
Git provides a convenient way to mark commits for squashing during development:
# Create a fixup commit
git commit --fixup=abc123
# Create a squash commit
git commit --squash=abc123
# Later, rebase with autosquash
git rebase -i --autosquash main
Rebase onto a Different Branch
Sometimes you need to move a branch to start from a different point:
# Move feature-auth to start from develop instead of main
git rebase --onto develop main feature-auth
Preserve Merge Commits
By default, rebase flattens merge commits. To preserve them:
git rebase --preserve-merges main
# Or in newer Git versions:
git rebase --rebase-merges main
Common Pitfalls and Troubleshooting
Never Rebase Shared Commits
This cannot be emphasized enough. If other developers have based work on your commits, rebasing will cause major headaches. The golden rule: only rebase commits that exist locally or in your personal fork.
Handling Complex Conflicts
When rebase conflicts seem overwhelming:
# Check which commit is causing issues
git status
# See the current state
git log --oneline --graph
# If things get messy, abort and try a different approach
git rebase --abort
# Consider using merge strategy
git merge main
Lost Commits After Rebase
Don’t panic if commits seem to disappear. Git’s reflog keeps track of all changes:
# See recent HEAD movements
git reflog
# Restore to a previous state
git reset --hard HEAD@{2}
Rebase Performance on Large Repositories
For repositories with thousands of commits, rebase can be slow. Some optimization techniques:
# Use single-threaded rebase for better error handling
git -c rebase.instructionFormat='%s [%an]' rebase -i HEAD~10
# For large histories, consider:
git config rebase.abbreviateCommands true
git config sequence.editor true
Best Practices and Workflow Integration
Team Workflow Guidelines
- Feature branches: Always rebase feature branches onto main before creating pull requests
- Personal branches: Use interactive rebase to clean up commits before sharing
- Shared branches: Use merge instead of rebase to avoid history conflicts
- Release branches: Never rebase release branches that others might depend on
Configuring Git for Better Rebase Experience
# Set up helpful aliases
git config --global alias.rb 'rebase'
git config --global alias.rbi 'rebase -i'
git config --global alias.rbc 'rebase --continue'
git config --global alias.rba 'rebase --abort'
# Configure default rebase behavior
git config --global pull.rebase true
git config --global rebase.autoStash true
git config --global rebase.autoSquash true
Integration with Development Tools
Most modern development environments support rebase operations through GUI tools. However, understanding the command line is crucial for troubleshooting. Popular tools that support rebase include:
- Visual Studio Code with Git extensions
- GitKraken for visual branch management
- IntelliJ IDEA’s built-in Git support
- Sourcetree for comprehensive Git operations
Performance Considerations and Server Impact
When working with Git repositories on servers, especially in development environments like those provided by VPS services or dedicated servers, consider the resource impact of rebase operations:
Operation | CPU Usage | Memory Usage | Disk I/O | Network Impact |
---|---|---|---|---|
Simple rebase (10 commits) | Low | Minimal | Low | None (local) |
Interactive rebase (100+ commits) | Medium | Moderate | High | None (local) |
Force push after rebase | Low | Low | Medium | High |
Rebase with conflicts | Variable | High | High | None (local) |
Advanced Troubleshooting and Recovery
Recovering from Rebase Disasters
Even experienced developers sometimes mess up a rebase. Here’s how to recover:
# Find the commit before rebase started
git reflog --all --grep="rebase"
# Or look for the backup Git creates
git log --walk-reflogs --oneline
# Restore to the original state
git reset --hard ORIG_HEAD
# If ORIG_HEAD doesn't work, use reflog
git reset --hard HEAD@{5} # Adjust number as needed
Dealing with Binary Files and Large Assets
Rebase can be problematic with large binary files. Consider these strategies:
# Use Git LFS for large files
git lfs track "*.psd"
git lfs track "*.zip"
# Skip binary file conflicts during rebase
git config merge.ours.driver true
echo "*.dll merge=ours" >> .gitattributes
Automation and Scripting
For repetitive rebase operations, create scripts to handle common scenarios:
#!/bin/bash
# Script: update-feature-branch.sh
# Usage: ./update-feature-branch.sh feature-name
FEATURE_BRANCH=$1
MAIN_BRANCH="main"
git checkout $MAIN_BRANCH
git pull origin $MAIN_BRANCH
git checkout $FEATURE_BRANCH
git rebase $MAIN_BRANCH
if [ $? -eq 0 ]; then
echo "Rebase successful!"
git push --force-with-lease origin $FEATURE_BRANCH
else
echo "Rebase failed. Please resolve conflicts manually."
fi
Integration with CI/CD and Development Workflows
Modern development workflows often integrate rebase operations with continuous integration systems. Here are some patterns that work well:
- Pre-commit hooks: Automatically rebase feature branches before allowing commits
- Pull request automation: Use GitHub Actions or GitLab CI to suggest rebase when branches are behind
- Branch protection: Require linear history by blocking merge commits on main branches
- Automated cleanup: Scripts that periodically clean up abandoned branches and suggest rebases
Git rebase is a powerful tool that, when used correctly, can significantly improve your project’s commit history and development workflow. The key is understanding when to use it, when to avoid it, and how to recover when things go wrong. Start with simple rebase operations on local branches, gradually work up to interactive rebasing, and always remember the golden rule: never rebase commits that others have based work on.
For more detailed information about Git rebase options and advanced use cases, check out the official Git documentation and the comprehensive Pro Git book chapter on rebasing.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.