Skip to main content
Rebasing is one of Git’s most powerful features for rewriting history. It allows you to transplant a series of commits onto a different starting point, creating a cleaner, more linear history.
Rebasing rewrites commit history. Never rebase commits that have been pushed to a shared repository and that others may have based work on.

What is Rebasing?

Rebasing takes a series of commits and “replays” them on top of a different base commit. Unlike merging, which creates a new commit to join two branches, rebasing rewrites the commit history to make it appear as if the work was done sequentially.
Before rebase:              After rebase:
      A---B---C topic              A'--B'--C' topic
     /                            /
D---E---F---G master    D---E---F---G master

Basic Rebasing

1
Update your topic branch
2
To rebase your current branch onto master:
3
git checkout topic
git rebase master
4
Or use the shorthand:
5
git rebase master topic
6
Resolve conflicts if they occur
7
If Git encounters conflicts during the rebase:
8
  • Fix the conflicts in the affected files
  • Stage the resolved files: git add <filename>
  • Continue the rebase: git rebase --continue
  • 9
    Alternatively:
    10
  • Skip the current commit: git rebase --skip
  • Abort the entire rebase: git rebase --abort
  • Interactive Rebase

    Interactive rebasing gives you complete control over your commit history, allowing you to reorder, edit, squash, or drop commits.
    git rebase -i HEAD~5
    
    This opens an editor with a list of commits:
    pick deadbee Implement feature XXX
    pick fa1afe1 Fix typo in feature XXX
    pick c0ffeee Add tests for feature XXX
    

    Available Commands

    • pick - Use the commit as-is
    • reword - Use the commit, but edit the commit message
    • edit - Use the commit, but stop for amending
    • squash - Combine this commit with the previous one, keeping both messages
    • fixup - Like squash, but discard this commit’s message
    • drop - Remove the commit entirely
    • exec - Run a shell command after this line

    Example: Cleaning Up Commits

    pick deadbee Implement feature XXX
    fixup fa1afe1 Fix typo in feature XXX
    pick c0ffeee Add tests for feature XXX
    exec make test
    
    This squashes the typo fix into the original commit and runs tests after applying the test commit.

    Advanced: Rebase with —onto

    The --onto option allows you to transplant a branch from one base to another.

    Transplanting a Topic Branch

    Suppose topic is based on next, but you want to move it to master:
        o---o---o---o---o  master
             \
              o---o---o---o---o  next
                               \
                                o---o---o  topic
    
    To rebase topic onto master:
    git rebase --onto master next topic
    
    Result:
        o---o---o---o---o  master
            |            \
            |             o'--o'--o'  topic
             \
              o---o---o---o---o  next
    

    Removing Commits from History

    To remove commits F and G from a branch:
        E---F---G---H---I---J  topicA
    
    git rebase --onto topicA~5 topicA~3 topicA
    
    Result:
        E---H'---I'---J'  topicA
    

    Handling Merge Commits

    By default, rebase drops merge commits. To preserve the branch structure, use --rebase-merges:
    git rebase --rebase-merges master
    
    This recreates merge commits during the rebase, maintaining your branch topology.

    Autosquash Workflow

    Use special commit messages to automatically mark commits for squashing:
    # Make a commit
    git commit -m "Add feature"
    
    # Later, create a fixup commit
    git commit --fixup=<commit-hash>
    
    # Rebase with autosquash
    git rebase -i --autosquash main
    
    Git will automatically arrange the fixup commits to be squashed into their targets.

    Recovering from Upstream Rebase

    If someone rebases commits you’ve based work on, you’ll need to rebase your work onto the new commits.
    1
    Identify the old base
    2
    After upstream rebases, find where the old branch tip was:
    3
    # Using reflog
    git reflog show subsystem
    
    # The old tip is at subsystem@{1}
    
    4
    Rebase onto the new base
    5
    git rebase --onto subsystem subsystem@{1}
    

    Rebase vs. Merge

    AspectRebaseMerge
    HistoryLinear, cleanerShows actual development history
    ConflictsResolved per commitResolved once
    SafetyRewrites historyPreserves history
    Use caseLocal cleanup, feature branchesIntegrating shared work

    Best Practices

    1. Never rebase public commits - Once commits are pushed and shared, rebasing them forces everyone downstream to fix their history
    2. Rebase before pushing - Clean up your local commits before sharing them
    3. Use interactive rebase for cleanup - Squash “fix typo” and “oops” commits before pushing
    4. Test after rebasing - Each rebased commit should still compile and pass tests. Use git rebase -i --exec "make test"
    5. Keep ORIG_HEAD in mind - Git saves your pre-rebase position in ORIG_HEAD, so you can recover with git reset --hard ORIG_HEAD

    Common Scenarios

    Updating a Feature Branch

    # Update main and rebase your feature
    git fetch origin
    git rebase origin/main
    

    Splitting a Commit

    1. Start interactive rebase: git rebase -i <commit>^
    2. Mark the commit for editing: change pick to edit
    3. Reset to before the commit: git reset HEAD^
    4. Stage and commit changes separately
    5. Continue: git rebase --continue

    Cleaning Up Before Merging

    # Squash all commits since branching from main
    git rebase -i main
    
    # In the editor, keep the first commit as 'pick'
    # Change others to 'squash' or 'fixup'
    

    Configuration Options

    Useful rebase configurations in your .gitconfig:
    [rebase]
        # Automatically stash before rebasing
        autoStash = true
        
        # Automatically apply fixup and squash commits
        autoSquash = true
        
        # Show a diffstat of changes after rebase
        stat = true
    

    Troubleshooting

    Rebase Stopped with Conflicts

    Check which files have conflicts:
    git status
    
    See the current patch being applied:
    git rebase --show-current-patch
    

    Accidentally Started a Rebase

    Abort and return to the original state:
    git rebase --abort
    

    Rebase Completed but Something’s Wrong

    Reset to the state before rebasing:
    git reset --hard ORIG_HEAD