Skip to main content
๐Ÿ›ก๏ธ Verified Technical Content: Written by Serhii Hrekov. | Last reviewed & updated in Git: July 21, 2026

Git Rebase: The Complete Guide to Rebasing, Undoing, and Advanced Workflows

ยท 11 min read
Serhii Hrekov
Senior Software Engineer & System Architect specializing in Python, Web Systems, Cloud Infrastructure & Automation

Rebasing is one of Git's most powerful and frequently misunderstood tools. While merging integrates changes by creating a new merge commit, rebasing rewrites history by moving your commits onto a new base. This creates a clean, linear commit history.

However, rewriting history comes with risks. This guide covers how to rebase onto main, resolve conflicts, undo mistakes, utilize advanced interactive workflows, and when to avoid rebasing entirely.


How to Rebase a Feature Branch onto Mainโ€‹

Rebasing is highly effective when updating your local feature branch with the latest commits from the remote main branch before opening a pull request.

The Rebase Workflowโ€‹

  1. Switch to your feature branch:
    git switch my-feature-branch
  2. Fetch the latest remote changes:
    git fetch origin
    This ensures your local copy of origin/main is completely up to date.
  3. Rebase your branch:
    git rebase origin/main
    Git will temporarily lift your local commits, apply the new remote commits from main, and then replay your commits on top.

Resolving Rebase Conflictsโ€‹

If your branch edits the same lines as the remote branch, Git will pause the rebase.

  1. Open the conflicted files and manually resolve the conflict markers (<<<<<<<, =======, >>>>>>>).
  2. Stage the resolved files:
    git add path/to/conflicted_file
  3. Continue the rebase:
    git rebase --continue
    (Repeat this process for any subsequent commits. Do not run git commit during a rebase).

Aborting a Rebaseโ€‹

If the conflicts are too complex or you make a mistake, you can safely cancel the entire operation and restore your branch to its original state:

git rebase --abort

Pushing After a Rebaseโ€‹

Because rebasing rewrites history, Git will reject a standard git push. You must force the push. Always use --force-with-lease instead of a plain --force:

git push --force-with-lease

The --force-with-lease flag is a safety check: it refuses to push if someone else has pushed new commits to the remote feature branch since you last pulled.


There are two primary situations where you should avoid rebasing:

1. Public or Shared Branchesโ€‹

You should never rebase a branch that has been pushed to a remote repository and pulled by other developers (3).

  • Why: Rebasing replaces your original commits with brand new ones. If other developers are already working on top of your original commits, their local history will no longer match the remote history. When they try to sync, they will be forced to merge divergent histories, leading to severe merge conflicts and duplicated commits.
  • Alternative: Use git merge for shared branches. It preserves original commits and records the exact merge point explicitly.

2. When Preserving Raw Historical Context is Criticalโ€‹

A linear git log is clean, but it hides the exact chronological order of how features converged. If you need to trace the exact, unedited timeline of when development paths crossed or keep track of every individual micro-commit, stick to git merge.


How to Undo a Completed Git Rebaseโ€‹

If you successfully completed a rebase but realize it introduced bugs or was done on the wrong branch, you can revert it.

Method A: Undoing Local-Only Rebasesโ€‹

If you haven't pushed the rebased branch yet, you can reset your branch pointer using the Git reflog (5).

  1. View your HEAD history using git reflog:
    git reflog
    The output will look similar to this:
    a1b2c3d HEAD@{0}: rebase (finish): returning to refs/heads/my-feature-branch
    e4f5g6h HEAD@{1}: rebase (start): checkout origin/main
    i7j8k9l HEAD@{2}: commit: Add validations to login form
  2. Locate the commit hash before the rebase started. In the log above, HEAD@{2} (commit i7j8k9l) was the last commit before the rebase began.
  3. Reset your branch to that commit:
    git reset --hard HEAD@{2}
    (Alternatively, you can run git reset --hard ORIG_HEAD immediately after the rebase completes, as Git stores the pre-rebase HEAD in the ORIG_HEAD variable. However, this is overwritten by subsequent dangerous commands).

Method B: Reverting a Pushed Rebaseโ€‹

If you already force-pushed the rebased branch to a shared repository, running git reset --hard and force-pushing again will disrupt your team. The safest approach is to use git revert to apply inverse changes (6).

  1. Find the commits introduced during the rebase by comparing your branch to main:
    git log main..my-feature-branch
  2. Create new commits that revert the changes:
    git revert <commit-hash-1> <commit-hash-2>
  3. Push the new revert commits to the remote:
    git push

Advanced & Unusual Git Rebase Workflowsโ€‹

Beyond basic updating, git rebase can be used to clean up local commits or restructure branches.

1. Interactive Rebase (git rebase -i)โ€‹

Interactive mode allows you to edit, combine, or delete commits in your branch history. This is ideal for cleaning up "work-in-progress" commits before opening a pull request.

To edit the last 5 commits:

git rebase -i HEAD~5

This opens your text editor with a list of commits prefixed by commands:

pick 623f71c Add user login form
pick 1b7c84a Fix typo in user model
pick d9e8f2e Add validations to login form
pick 5a4b3d1 Forgot to add a file, adding it now

You can change pick to other commands:

  • reword (r): Keeps the commit contents but lets you rewrite the commit message.
  • squash (s): Combines the commit with the previous one and prompts you to merge the commit messages.
  • fixup (f): Combines the commit with the previous one but discards its commit message (perfect for quick typo fixes).
  • drop (d): Removes the commit entirely.

2. Splitting a Commitโ€‹

If you made a large commit that should be split into smaller, independent commits:

  1. Run interactive rebase and mark the target commit as edit:
    edit bf123ac Add user profile page and refactor API calls
  2. Save and close the editor. Git will pause at the target commit.
  3. Reset the commit pointer without losing your files:
    git reset HEAD^
  4. Stage and commit the first group of files:
    git add src/components/Profile.js
    git commit -m "Add user profile page"
  5. Stage and commit the remaining changes:
    git add src/utils/api.js
    git commit -m "Refactor API calls"
  6. Complete the rebase:
    git rebase --continue

3. Restructuring Branches with git rebase --ontoโ€‹

The --onto flag allows you to transplant a series of commits from their current base to a new one.

Suppose you have a feature branch my-feature branched off main at commit C, but you want to move it to a different branch new-base.

Before:
A -- B -- C -- D (main)
\
E -- F -- G (my-feature)

To move commits E, F, and G onto new-base:

git rebase --onto new-base C my-feature
After:
A -- B -- C -- D (main)
\
H -- I (new-base)
\
E -- F -- G (my-feature)

Sourcesโ€‹