Git Rebasing

By Vishvesh Patel · DevOps EngineerUpdated September 16, 2026

Replay commits for a linear history. Basic and interactive rebase, squashing, recovering with --abort and reflog, force-with-lease, and when to merge instead.

What Rebase Does

Rebase moves or reapplies commits onto a new base commit. Instead of combining two branches with a merge commit, rebase rewrites the branch so it appears to start from a later point in history.

Suppose feature/login was created from main, but main has advanced since then. Rebasing feature/login onto main replays the feature branch commits on top of the newer main.

git switch feature/login
git rebase main

This can make history look cleaner and more linear.

Tip: Rebase rewrites commit history. That is powerful, but it means you should be careful with commits other people are already using.

Why Developers Rebase

Common reasons to use rebase include:

  • updating a feature branch with the latest main
  • cleaning up commit history before a pull request
  • squashing many small commits into one logical commit
  • reordering or editing recent commits

Rebase does not add new project content by itself. It changes how commits are arranged in history.

Basic Rebase Example

Imagine this history:

  • main: A → B → C
  • feature/login: A → D → E

After rebasing feature/login onto main, the feature becomes:

  • main: A → B → C
  • feature/login: A → B → C → D' → E'

The apostrophes matter. Git usually creates new commit IDs because it is replaying the changes, not simply moving old commits.

Use:

git switch feature/login
git rebase main

If everything applies cleanly, you get the same code changes on a newer base.

Rebase Conflicts

Rebase can produce conflicts just like merge. When that happens, Git pauses and asks you to resolve them.

A typical flow looks like this:

git rebase main
git status

Edit the conflicted file, remove conflict markers, then continue:

git add app.js
git rebase --continue

If another conflict appears, repeat the process.

If you want to stop and return to the original state:

git rebase --abort

Interactive Rebase with -i

Interactive rebase lets you edit a series of recent commits. It is one of the most useful cleanup tools in Git.

To review the last three commits:

git rebase -i HEAD~3

Git opens your editor with something like:

pick a1b2c3d Add login form
pick d4e5f6g Fix typo in login form
pick h7i8j9k Update login button color

You can change the action for each commit.

Common Interactive Actions

  • pick: keep the commit as is
  • reword: keep the content but edit the message
  • edit: pause so you can modify the commit
  • squash: combine this commit with the previous one
  • drop: remove the commit

Squashing Commits

Suppose your history contains several tiny “fix typo” commits that belong with the main feature. Interactive rebase can combine them.

Example:

pick a1b2c3d Add login form
squash d4e5f6g Fix typo in login form
squash h7i8j9k Update login button color

After saving, Git combines the commits and lets you write a final commit message.

This is useful before opening a pull request because reviewers often prefer a clean, logical commit history.

Note: Squashing is best used on your own unpublished work. Avoid rewriting shared history unless your team explicitly agrees on that workflow.

Rebase vs Merge

Both rebase and merge combine lines of development, but they tell the story differently.

TopicMergeRebase
History shapePreserves branch structureCreates a more linear history
New commit IDsUsually no rewrite of existing commitsRewrites rebased commits
Safety for shared historySaferNeeds more care
Typical useIntegrating branchesCleaning history or updating a feature branch

Simple Rule of Thumb

  • Use merge when you want to preserve real branch history
  • Use rebase when you want a cleaner branch history before integration

A Safe Team Habit

A common safe habit is:

  1. Rebase your own feature branch onto the latest main
  2. Push the updated branch
  3. Merge it through a pull request

Example:

git switch main
git pull
git switch feature/login
git rebase main
git push --force-with-lease

--force-with-lease is safer than plain --force because it checks whether the remote changed in unexpected ways.

What You Should Remember

Rebase replays commits onto a new base, which can make history look cleaner. Interactive rebase is especially useful for rewording, reordering, or squashing recent commits. But because rebase rewrites history, it should be used carefully on shared branches.

If you are unsure, use merge. If you want a polished branch before review, rebase can be a great tool.

Test Your Understanding

Exercise 1: Understanding rebased commits

Scenario: Your feature branch had commits D and E, and you rebased it onto a newer main with commits A, B, and C.

Question: Why did the tutorial show the rebased branch as A -> B -> C -> D' -> E' instead of keeping the old D and E exactly?

Exercise

Exercise 1: Understanding rebased commits

Identify why rebased commits usually receive new identities.

Exercise 2: Cleaning up tiny commits

Scenario: Your feature branch contains Add login form, Fix typo in login form, and Update login button color as three small related commits.

Question: Which interactive rebase action from the tutorial is designed to combine the later two into the first logical commit?

Exercise

Exercise 2: Cleaning up tiny commits

Choose the interactive rebase action that combines related commits.

Exercise 3: Pushing a rebased branch safely

Question: After rebasing your own feature branch onto the latest main, why did the tutorial recommend git push --force-with-lease instead of plain --force?

Exercise

Exercise 3: Pushing a rebased branch safely

Pick the reason force-with-lease is safer after a history rewrite.


Frequently Asked Questions

What is the difference between git rebase and git merge?

Both integrate one branch into another; they differ in what history they leave behind. git merge creates a merge commit joining the two lines of development, preserving exactly what happened including the fact that work happened in parallel. git rebase replays your commits on top of the target branch, producing a straight line as though you had started from the latest code. Merge is honest about history and clutters the graph; rebase is tidy and rewrites commit hashes. Most teams rebase local feature branches before opening a pull request, then merge the result.

Is it safe to rebase a branch that has been pushed?

Only if you are the only person working on it. Rebasing creates new commits with new hashes, so the remote branch and your local one diverge and git push is rejected until you force it. Use git push --force-with-lease rather than --force: it refuses the push if someone else has added commits you have not seen, which turns silent data loss into an error message. Never rebase a shared branch such as main. Everyone who has pulled it will be stranded on commits that no longer exist.

How do I squash multiple commits into one?

Run git rebase -i HEAD~n where n is how many commits back you want to go, then change pick to squash (or s) on every commit except the first. The first stays pick because the others are folded into it. Git then opens an editor to combine the messages. If you only want the first commit's message, use fixup instead of squash to discard the others. Many platforms also offer "Squash and merge" on a pull request, which achieves the same result without rebasing locally.

How do I get out of a rebase that has gone wrong?

git rebase --abort returns the branch to exactly where it was before the rebase started, at any point during the process. That is the escape hatch to reach for whenever you are unsure. If the rebase has already completed and you want the old state back, git reflog lists where HEAD has been, and git reset --hard HEAD@{n} moves you to the entry before the rebase. The reflog is why a completed rebase is recoverable and why "I lost my work" is almost never actually true.

Why do I keep hitting the same conflict repeatedly during a rebase?

Because a rebase replays each commit in turn, so a line you changed in several commits conflicts once per commit. Resolve the file, git add it, then git rebase --continue to move to the next one. Two things help: squashing related commits before rebasing so there are fewer replays, and enabling git config --global rerere.enabled true, which records how you resolved a conflict and reapplies that resolution automatically the next time the identical conflict appears.

What does git pull --rebase do and should I use it?

It fetches the remote branch and replays your local commits on top of it, instead of creating a merge commit. Without it, a plain git pull on a branch that has moved on both sides produces a "Merge branch 'main' of ..." commit, and a busy repository fills with them. Setting git config --global pull.rebase true makes it the default and keeps history linear. It is safe for your own unpushed commits, which is exactly what git pull is dealing with.

Continue Learning

Explore Related Topics

When it breaks

Related Resources