Back to all articles
Git Rebase: Master Git History Rewriting with Confidence

Git Rebase: Master Git History Rewriting with Confidence

Learn to use git rebase like a professional: reorder, combine, and modify commits. Complete guide with examples, best practices, and interactive tool.

Human-architected research synthesized with the assistance of AI personas.
8 min read

TL;DR / Executive Summary

Learn to use git rebase like a professional: reorder, combine, and modify commits. Complete guide with examples, best practices, and interactive tool.

💡 TL;DR (Too Long; Didn't Read)

  • Git rebase allows you to rewrite commit history to create a linear and clean flow.
  • Use interactive rebase (rebase -i) to combine, edit, or reorder commits.
  • Avoid rebase on public branches to prevent synchronization issues.
  • The tool is powerful but requires caution to avoid losing work.

Git Rebase: The Definitive Guide to Reorganizing Your Commit History

Git is arguably the most popular version control tool among developers, but many still feel intimidated by one of its most powerful commands: git rebase. In this comprehensive guide, we'll completely demystify this tool, exploring its uses, advantages, pitfalls, and best practices.

What is Git Rebase and why should you care?

git rebase is a Git command that allows you to reorganize, modify, and clean up commit history. Unlike git merge, which joins branches keeping the complete history (including explicit merge commits), rebase "rewrites" history by applying commits on a new base.

The problem that rebase solves

Imagine you started working on a feature in a branch derived from main. While you develop, other team members continue integrating their changes into main. Your history starts to diverge, creating a complex structure that can make code review and understanding the development flow difficult.

Rebase solves this problem by allowing you to move your commits to the top of the most recent branch, creating a linear and clean history.

How Git Rebase works: The magic behind the command

Technically, rebase works by identifying the common ancestor between your current branch and the base branch, temporarily saving the commits from your branch, resetting the branch to the specified base, and then reapplying each commit one by one.

The step-by-step process:

  1. Common ancestor identification: Git finds where the two branches diverged.
  2. Difference storage: Your commits are converted into temporary patches.
  3. Reset to new base: Your branch is moved to the specified commit.
  4. Commit reapplication: Your changesets are applied sequentially on the new base.

Basic Rebase: Moving a branch to a new base

The simplest way to use rebase is to update a feature branch with the latest changes from the main branch:

bash
# Make sure you're on the branch you want to update git checkout my-feature # Get the latest remote changes git fetch origin # Rebase on the updated main branch git rebase origin/main

This command will take all unique commits from my-feature and reapply them on top of the latest origin/main.

Interactive Rebase: The real power of rebase

The true power of rebase is revealed with the -i (interactive) flag, which opens an editor where you can specify how each commit should be modified during the rebase process.

Starting interactive rebase:

bash
# Rebase the last 5 commits git rebase -i HEAD~5 # Rebase from a specific point git rebase -i origin/main

Interactive rebase options:

When running git rebase -i, you'll encounter these options:

  • pick: Keeps the commit unchanged.
  • reword: Keeps the changes but edits the commit message.
  • edit: Pauses the rebase to allow modifying the commit.
  • squash: Combines the commit with the previous one and allows merging messages.
  • fixup: Combines the commit with the previous one, discarding its message.
  • drop: Completely removes the commit.

Practical Rebase Use Scenarios

  1. Combining multiple commits (Squashing)

    One of the most common uses of rebase is combining several small commits into larger, more meaningful commits:

    bash
    # Start interactive rebase for the last 3 commits git rebase -i HEAD~3 # In the editor, change "pick" to "squash" or "fixup" for commits you want to combine
  2. Cleaning up history before a pull request

    Before submitting a pull request, it's good practice to clean up the history to facilitate review:

    bash
    # Make sure your branch is up to date git fetch origin git rebase origin/main # Run interactive rebase to clean up commits git rebase -i origin/main
  3. Fixing issues in old commits

    With edit in interactive rebase, you can stop at any commit to make modifications:

    bash
    # During rebase, when stopping at a commit marked as "edit": git commit --amend # Make your corrections git rebase --continue # Continue the process
  4. Splitting large changes into smaller commits

    Sometimes you need to do the opposite of squash - split a large commit into several smaller ones:

    bash
    # Mark a commit as "edit" in interactive rebase # When rebase pauses, reset to the commit but keep the changes: git reset HEAD~ # Commit changes in smaller parts git add -p # Add changes interactively git commit -m "Part 1 of changes" git commit -m "Part 2 of changes" # Continue the rebase git rebase --continue

Rebase vs Merge: When to use each

This is one of the great debates in the Git world. Here's a practical guide:

Use rebase when:

  • Working on unshared local branches.
  • Preparing commits for a pull request.
  • Wanting to create a linear and clean history.
  • Need to modify old commits.

Use merge when:

  • Working on public branches shared with others.
  • Preserving the complete history of how work was developed.
  • Integrating complete features into the main branch.

Common pitfalls and how to avoid them

  1. Never rebase public commits

    The golden rule of rebase: never rebase commits that have already been pushed to a public repository and may have been downloaded by other people. This causes history inconsistencies that are extremely difficult to resolve.

  2. Conflicts during rebase

    Unlike merge which resolves conflicts once, rebase may require resolving the same conflicts multiple times (for each reapplied commit). Be prepared to resolve conflicts sequentially.

  3. Recovering from a problematic rebase

    If you made a mistake during rebase, don't panic. Git maintains a temporary reference (ORIG_HEAD) pointing to where your branch was before the rebase:

    bash
    # Abort an ongoing rebase git rebase --abort # Revert a completed rebase git reset --hard ORIG_HEAD

Workflow with rebase: Best practices

  1. Keep feature branches updated regularly

    Instead of waiting until the end to integrate changes from the main branch, update frequently:

    bash
    # Daily, synchronize with the main branch git checkout main git pull git checkout my-feature git rebase main
  2. Use --rebase in pull for clean history

    Configure your Git to use rebase by default when pulling:

    bash
    git config --global pull.rebase true

    This avoids unnecessary merge commits when you do git pull.

  3. Review history before push

    Before sending your changes, review the history:

    bash
    git log --oneline --graph

    Make sure the history is as you expect before sharing with others.

Advanced rebase commands

Rebase with autostash

For rebase when there are uncommitted changes:

bash
git rebase --autostash origin/main

Git automatically stashes your changes, runs the rebase, and then reapplies the changes.

Selective rebase (--onto)

The rebase --onto command is powerful for complex scenarios:

# Suppose you have:
# A---B---C feature
#   \
#    D---E main
#         \
#          F---G other-feature

# To move F and G to after C:
git rebase --onto feature E other-feature

Integration with modern tools

Many modern IDEs and Git clients offer visual support for rebase, making the process more intuitive. However, understanding the commands behind graphical interfaces is crucial for solving problems when they arise.

Conclusion

git rebase is an extremely powerful tool that, when used appropriately, can transform a confusing Git history into a clear and linear narrative of project development. Master interactive rebase, understand when to use it versus merge, and always respect the rule of not rebasing public commits.

With practice, rebase will become a natural part of your workflow, allowing you to maintain a clean history that facilitates reading, debugging, and understanding your code's evolution.

Editor's Note

This post is a summary of our Interactive Git Rebase Simulator, a complete tool to demystify, visualize, and master one of Git's most powerful and misunderstood features.

Receive new articles

Subscribe to receive notifications about new articles directly to your email

We won't send spam. You can unsubscribe at any time.