What Is Interactive Rebase in Git?

What Is Interactive Rebase in Git?

An in-depth, zero-prior-knowledge guide to Git's interactive rebase — what it is, exactly how it rewrites commit history internally, how it fits into everyday GitHub workflows, and the real production habits, safeguards, and trade-offs engineering teams rely on when reshaping history on purpose.

Most of the time, Git history is something you simply add to — you commit, you commit again, and the story of your project grows forward, one entry at a time, like a diary. Interactive rebase breaks that assumption in a controlled, deliberate way. It lets you reopen recent pages of that diary and edit them: combine two rushed entries into one clear one, delete an entry that turned out to be a dead end, reorder entries so the story reads more logically, or simply reword a confusing sentence — all before anyone else ever reads that part of the diary. This single feature is one of the most powerful tools in Git, and also one of the most feared by newcomers, because it touches something Git otherwise treats as sacred: the permanence of history. This article walks through what interactive rebase actually is, how it works internally at the level of individual commits, how it flows through a real development session step by step, and the practices, safeguards, and trade-offs professional teams rely on when using it — including how it relates to GitHub’s own pull request workflows.

1Core Concepts

Before touching the mechanics, let’s build a precise mental model of what rebasing is in general, and what makes the “interactive” version fundamentally different from an ordinary rebase.

What Rebasing Means in the First Place

To understand interactive rebase, you first need to understand plain rebasing. In Git, a rebase takes a sequence of commits and replays them, one at a time, on top of a different starting point than where they were originally created. Imagine you started a new feature branch three days ago, and since then, three other commits have landed on the main branch. Rebasing your feature branch means Git temporarily sets your commits aside, moves your branch’s starting point forward to include those three new commits, and then reapplies your own commits on top, one by one, as if you had started your work today instead of three days ago. The end result looks as though your work happened after the latest changes, producing a clean, straight-line history with no crossing branches.

What Makes It “Interactive”

An ordinary rebase runs automatically from start to finish with no input from you beyond resolving conflicts if they occur. An interactive rebase inserts a deliberate pause before that replay begins: Git opens a text editor showing every commit about to be replayed, one per line, and lets you decide — commit by commit — exactly what should happen to it. Should it be kept exactly as is? Reworded? Merged into the commit before it? Dropped entirely? Split apart? Interactive rebase turns the otherwise mechanical process of “replay these commits” into an editable checklist you control before a single commit is actually replayed.

EVERYDAY ANALOGY

Picture editing a rough home video before sharing it with family. A plain rebase is like re-recording the same footage onto a new blank tape, unchanged, just starting from a later point. Interactive rebase is like opening a video editor first — trimming an awkward clip, merging two short clips into one smooth scene, deleting a blurry take, reordering scenes so the story flows better — before that final version ever gets recorded onto the tape you actually share.

The Fundamental Trade Rebasing Makes

Every rebase, interactive or not, makes the exact same trade: it produces a cleaner-looking history in exchange for creating entirely new commits. This is worth stating plainly, because it surprises many newcomers — a rebased commit is never truly “the same commit, moved.” Git commits are identified by a hash calculated from their content, including their parent commit. The instant a commit’s parent changes, as it does the moment it’s replayed onto a new base, its hash changes too, which means rebasing always produces brand-new commit objects, even when the actual code change inside them looks byte-for-byte identical to the original.

REBASE

Moves the Starting Point

Replays a sequence of commits onto a different base commit, producing a straight-line history instead of a branching one.

INTERACTIVE

Adds a Planning Step

Pauses before replaying to let you edit, reorder, combine, split, or remove commits through an editable todo list.

NEW HASHES

Rewrites, Doesn’t Move

Every rebased commit is a genuinely new object with a new identifier, since a commit’s hash depends on its parent commit.

LOCAL FIRST

A Personal History Tool

Most safely used on commits that exist only on your own machine, before they’ve been shared with anyone else — a theme this article returns to repeatedly.

i
KEY TAKEAWAY

Interactive rebase doesn’t edit existing commits in place — it’s better understood as “throw these commits away and carefully build a new, improved sequence to replace them.” Once you internalize that rebasing always creates new history rather than modifying old history, its behavior, its power, and its risks all become far more predictable.

How Interactive Rebase Relates to Ordinary Commit Amending

Many developers first meet the idea of rewriting history through a much smaller, simpler command that lets you fold new changes into your single most recent commit — a convenient shortcut, but one that only ever reaches backward exactly one commit. Interactive rebase is best understood as the general, fully extended version of that same underlying idea: instead of being limited to only your very last commit, it opens up an entire chosen range of recent commits at once, letting you apply that same kind of correction, reordering, or removal to any of them, not just the most recent one. Developers who are already comfortable amending their latest commit typically find interactive rebase a natural, logical next step, rather than an entirely unfamiliar concept.

Choosing How Far Back to Rebase

Every interactive rebase requires you to specify a starting point — either a specific commit to rebase onto, or a count of how many recent commits to include, measured backward from your current position. Choosing this starting point correctly matters: pick too few commits, and the cleanup you want to perform on an earlier commit won’t even appear in your editable plan; pick too many, and you risk pulling in commits that were already shared with others, reopening exactly the sharing risks discussed later in this article. A useful habit is to first look at a graphical view of recent history to visually confirm exactly which commits are still private to you before deciding how far back the rebase should reach.

2Architecture & Components

Interactive rebase is built from a small, well-defined set of moving parts: a todo list, a set of commands you can assign to each line, and a temporary working state Git maintains while the rebase is in progress.

The Todo List

The centerpiece of interactive rebase is a plain text file Git generates and opens in your configured text editor the moment the rebase begins. Every commit scheduled to be replayed appears as one line, listed in the order it was originally created, each prefixed with a command word — pick by default — followed by that commit’s short identifier and its message. This file is exactly as editable as any other plain text file: you can delete lines, reorder them, and change the command word at the start of each one. Once you save and close it, Git reads your edited instructions and begins carrying them out, one line at a time, from top to bottom.

The Command Vocabulary

Each line in the todo list can be assigned one of several commands, and understanding all of them is really understanding the full toolbox interactive rebase offers.

CommandEffectTypical Use
pickKeep the commit exactly as it isThe default for any commit needing no change
rewordKeep the change, but pause to let you edit the commit messageFixing a typo or unclear message written in a hurry
editPause the rebase entirely at this commit, letting you amend its contentAdding a forgotten file, splitting a commit, or adjusting the change itself
squashCombine this commit into the one directly above it, merging both messagesMerging two small, related commits into one meaningful one
fixupSame as squash, but silently discards this commit’s own messageFolding a “quick fix” commit into the commit it’s correcting
dropRemove this commit and its change entirely from historyDeleting an experimental or accidental commit
execRun an arbitrary shell command at this point in the sequenceRunning tests after each commit to verify nothing was broken along the way

Temporary State During the Rebase

While an interactive rebase is in progress, Git maintains a set of temporary bookkeeping files describing exactly where it is in the process — which commit it’s currently working on, which commands remain, and what the original branch position was before the rebase began. This temporary state is what allows you to pause partway through (when using edit, or when a conflict occurs), make changes, and then tell Git to continue exactly where it left off, rather than needing to restart the whole sequence from scratch.

COMPONENT

The Todo List

Your editable plan — the sequence of commits and the command assigned to each one, read once at the very start of the rebase.

COMPONENT

The Replay Engine

The internal process that actually applies each planned change onto the new base, one commit at a time, in the order you specified.

COMPONENT

The Pause Points

Moments the replay engine deliberately stops — for a reword, an edit, or a conflict — handing control back to you before continuing.

COMPONENT

The Original Position

A saved reference to where your branch pointed before the rebase started, which is exactly what makes aborting or undoing a rebase possible.

!
COMMON TRAP

The order of lines in the todo list is not just cosmetic — reordering two lines genuinely changes the order those changes are replayed in, which can occasionally cause a conflict that didn’t exist in the original history, especially when two commits touch overlapping code.

3Internal Working

Now let’s open the hood and trace exactly what Git does internally, from the moment you start an interactive rebase to the moment it finishes.

Step One: Building the Plan

When you start an interactive rebase, Git first identifies exactly which commits sit between your chosen new base and your branch’s current tip — this range becomes the todo list’s contents. Git writes this list to a temporary file and opens it in your text editor, then waits. Nothing about your repository’s actual history changes yet at this point; you’re purely editing a plan, not touching real commits.

Step Two: Detaching and Replaying

Once you save your edited plan, Git moves your working position to the new base commit, entering what’s called a “detached HEAD” state — meaning your current position temporarily isn’t pointing at the tip of any named branch, only at a specific commit. From there, the replay engine works through your todo list top to bottom. For each picked commit, Git essentially computes the exact code change that commit originally introduced, then attempts to apply that same change on top of whatever the history currently looks like at this new position, before creating a fresh commit to record it.

flowchart TD
    A["Start: git rebase -i"] --> B["Git builds todo list\nfrom commit range"]
    B --> C["Editor opens\nfor you to edit plan"]
    C --> D["You save and close"]
    D --> E["HEAD detaches to\nnew base commit"]
    E --> F["Replay engine processes\neach line top to bottom"]
    F -->|pick/squash/fixup| G["New commit created\nwith new hash"]
    F -->|reword/edit| H["Rebase pauses for\nyour input"]
    F -->|conflict| I["Rebase pauses for\nconflict resolution"]
    G --> F
    H --> F
    I --> F
    F -->|todo list complete| J["Branch pointer moves\nto final new commit"]
    

Fig 1 — Interactive rebase builds a plan first, then detaches and replays commits one at a time, pausing whenever your instructions or a conflict require it.

Step Three: Handling Each Command Internally

A reword command causes the replay engine to apply the change exactly as normal, but instead of automatically reusing the original commit message, it pauses and opens your editor so you can supply a new one before the commit is finalized. An edit command applies the change and then stops completely, leaving you in that detached state with the commit already made, free to modify files, stage additional changes, or amend the commit however you like, before manually telling Git to resume the rebase. A squash or fixup command doesn’t create a separate commit at all — instead, it combines the change with the commit immediately above it in the plan, producing one single new commit representing both changes together, with squash prompting you to merge or edit both original messages and fixup silently discarding the folded-in commit’s message. A drop command simply skips a commit’s change entirely, as though it never existed in the replayed history.

Step Four: Finishing the Rebase

Once every line in the todo list has been processed, Git moves your original branch name to point at the final new commit produced by the replay — completing the transition from detached HEAD back to a proper, named branch position. At this point, the rebase is finished: your branch now points to an entirely new chain of commits, structurally similar to the original sequence in content, but different in nearly every hash along the way.

EVERYDAY ANALOGY

Think of retyping a messy, handwritten rough draft into a clean, final manuscript. You read the original page by page, deciding for each one whether to type it as-is, fix a typo while retyping it, merge two short paragraphs into one, or skip a paragraph entirely. The final manuscript resembles the original closely, but every single page has genuinely been retyped — none of the original handwritten pages were edited in place; they were replaced by newly written ones.

Why Conflicts Can Appear Mid-Rebase

Because each commit is replayed as an independent change against whatever the code currently looks like at that point in the sequence, a change that applied perfectly well in the original history can sometimes fail to apply cleanly against a different base or a different surrounding sequence of commits. When this happens, the replay engine pauses exactly like it does for edit, leaving conflict markers in the affected files for you to resolve by hand before telling Git to continue with the remaining commits in the plan.

Understanding the Detached HEAD State

The “detached HEAD” state mentioned earlier is one of the most misunderstood moments in all of Git, largely because the terminology sounds more alarming than the reality actually is. Normally, your current position is described relative to a named branch — you’re “on” a branch, and that branch’s name automatically follows you forward as you commit. During an interactive rebase, however, you’re working with commits that don’t yet belong to any branch at all; they’re being constructed one at a time in a kind of temporary staging area. Only once the entire todo list finishes processing does Git take that finished sequence and attach your original branch name back onto it. This is precisely why interrupting a rebase partway through — closing your terminal, restarting your machine — doesn’t lose your original branch position; the branch name itself never actually moved until the very last step, and the reflog, covered in detail later, preserves exactly where things stood in the meantime.

4Data Flow & Lifecycle

Let’s trace a realistic, complete interactive rebase from start to finish, the way it actually unfolds during a normal development session.

1

Recognizing the Need

A developer finishes a feature across eight small commits — several are quick fixes to earlier commits in the same branch, one has a typo in its message, and two are exploratory commits that ended up unused.

2

Starting the Rebase

The developer starts an interactive rebase targeting the commit just before their first change, bringing all eight of their own commits into the editable todo list.

3

Planning the Cleanup

In the editor, the two unused exploratory commits are marked drop, the quick-fix commits are marked fixup and moved directly beneath the commits they correct, and the commit with the typo is marked reword. Every remaining commit stays as pick.

4

Saving and Replaying

The developer saves the plan. Git detaches HEAD and works through it: dropping the two exploratory changes, silently folding each fix into its target commit, and pausing once to let the developer correct the typo’d message before continuing automatically through the rest.

5

Resolving a Conflict

One of the fixup commits doesn’t apply cleanly, since the surrounding code shifted slightly during the reordering. The rebase pauses; the developer resolves the conflict manually, stages the resolution, and tells Git to continue.

6

Completion

The rebase finishes, having turned eight messy, exploratory commits into four clean, well-messaged ones. The branch now points at this new, rewritten sequence, ready for review.

How the Rebased Branch Reaches Everyone Else

None of this history rewriting affects anyone else until the rebased branch is shared — typically by pushing it to a remote repository like GitHub. Because every commit in the rewritten sequence has a new hash, a normal push will be rejected: the remote still holds the old sequence, and Git can tell the histories no longer share a simple, linear relationship. Sharing rebased history requires an explicit, deliberate override — usually a force push — which is exactly why interactive rebase carries real coordination risk once other people are involved, a topic explored fully in the Security chapter.

“Interactive rebase doesn’t touch a single existing commit — it carefully writes a whole new sequence, then quietly points your branch at it.”

Interactive Rebase Inside a GitHub Pull Request Workflow

In a typical GitHub-based workflow, interactive rebase most commonly happens before a pull request is opened, or in response to review feedback while it’s still open — a developer cleans up their local commits, then pushes the rewritten history to update the same pull request branch. It’s worth distinguishing this clearly from GitHub’s own “rebase and merge” button, which performs a different, non-interactive rebase automatically at merge time to keep the target branch’s history linear; that button gives you no todo list and no opportunity to reword, squash, or drop commits — it simply replays the pull request’s existing commits as-is onto the latest target branch.

5Advantages, Disadvantages & Trade-offs

Interactive rebase is a genuinely powerful tool, but every bit of that power comes paired with a corresponding responsibility and risk.

ADVANTAGES

  • Produces a clean, readable, linear commit history that’s far easier to review and understand later
  • Lets a developer separate the messy reality of how code was actually written from the polished story worth preserving
  • Gives fine-grained control — reword, combine, split, reorder, or remove — over exactly what history should say
  • Makes tools like line-by-line blame and bisecting for bugs dramatically more useful against a clean, well-organized history
  • Encourages a habit of small, frequent local commits during development, since they can always be cleaned up before sharing

DISADVANTAGES & TRADE-OFFS

  • Rewrites commit hashes, which breaks history continuity for anyone who already has a copy of the old commits
  • Requires a force push to share, which can silently discard others’ unmerged work if used carelessly on a shared branch
  • Introduces genuine risk of losing work if a conflict or mistake mid-rebase isn’t handled carefully
  • Adds real cognitive overhead — understanding pick, squash, fixup, and edit correctly takes deliberate practice
  • Can obscure the true, original timeline of how a feature was actually developed, which is sometimes valuable context to keep

The Core Trade-off: A Polished Story Versus an Honest Record

At its heart, interactive rebase forces a philosophical choice every team eventually has to make explicitly or implicitly: should commit history read like a polished, edited final draft, or like an honest, unedited record of exactly how the work actually happened, mistakes and all? There’s no universally correct answer — a clean, rebased history is easier to read and review months later, while an unedited history preserves a more complete, sometimes more informative record of the real development process, including false starts that occasionally turn out to matter.

When a Clean History Pays Off

Months after a feature ships, a team uses a bug-hunting technique that automatically tests a range of past commits to pinpoint exactly which one introduced a regression. This technique works dramatically better against a rebased history of a handful of clean, logically scoped commits than against dozens of raw, minute-by-minute commits like “wip,” “fix typo,” and “actually fix it this time” — precisely the kind of noisy history interactive rebase is designed to clean up before it ever reaches shared history.

Weighing the Trade-off in Practice

In practice, most experienced teams don’t treat this as an all-or-nothing philosophical stance but as a question of scope. The messy, exploratory reality of how a feature was actually built rarely needs to be preserved forever — what matters long-term is usually the finished, reasoned-about result, not every wrong turn taken along the way. At the same time, throwing away that context too aggressively, or too early, can occasionally erase genuinely useful information, such as an earlier attempt that reveals why a particular approach was ultimately rejected. The most common resolution is to apply interactive rebase liberally to private, in-progress work, where the messy reality has little lasting value, while being far more conservative about rewriting anything that has already been reviewed, discussed, or built upon by someone else, where the honest record starts to carry real, lasting value of its own.

6Security

Because interactive rebase rewrites history, it introduces risks that don’t exist during ordinary, forward-only development — both to project integrity and, in specific cases, to genuine security.

The Core Danger: Force-Pushing Over Shared History

The single most dangerous action connected to interactive rebase isn’t the rebase itself — it’s force-pushing the rewritten history to a branch other people are actively working from. Because the rewritten commits have entirely new hashes, an ordinary push is rejected outright; overriding that rejection with a force push tells the remote to simply accept your version as correct, discarding whatever it previously held at that branch name. If a teammate had already pushed additional commits on top of the old history in the meantime, a careless force push can make those commits effectively unreachable from the branch name anyone uses to find them.

!
CRITICAL WARNING

Never interactively rebase, and never force-push, a branch that other people are actively basing their own work on — such as a shared main or release branch — without explicit team-wide coordination. The safest default rule many teams adopt is simple: only rebase branches you alone are working on, and only force-push to branches you alone own, such as your own personal feature branch.

Safer Force-Pushing

Git provides a safer variant of force-pushing specifically designed to reduce this risk — one that first checks whether the remote branch still matches what you last saw locally before overwriting it, and refuses the push if someone else has added commits you don’t yet have. This doesn’t eliminate the underlying risk of rewriting shared history, but it does prevent the single most common accident: silently overwriting a teammate’s work you simply hadn’t fetched yet.

Many hosting platforms, GitHub included, add another layer of protection on top of this at the repository level: administrators can configure specific branches, such as the main branch, to reject force pushes entirely, regardless of who is attempting them or which safety flags they use locally. This kind of server-side enforcement is generally considered the most reliable safeguard of all, since it doesn’t depend on every individual developer remembering to use the safer command-line option correctly every single time — it simply makes the dangerous action impossible against the branches an organization has decided are too important to risk rewriting.

Rewriting History to Remove Sensitive Data

Interactive rebase, and history rewriting more broadly, is sometimes used deliberately as a security response — specifically, to remove a secret or credential that was accidentally committed before anyone noticed. Using edit on the offending commit lets you amend it to remove the sensitive file or value, after which every commit that follows is automatically replayed on top of the corrected version, producing a history that no longer contains the secret anywhere in its normal chain. It’s essential to remember, however, that this alone is not a complete remedy: the old, unrewritten commits may still exist in reflogs, existing clones, forks, or cached views on a hosting platform, so any exposed credential should still be treated as compromised and rotated immediately, exactly as covered for other forms of accidental exposure in Git.

RULE 1

Own What You Rebase

Rebase branches only you are working on, never a shared branch others are actively building on top of.

RULE 2

Prefer Safer Force-Pushing

Use the safety-checked variant of force push by default, so an unexpected remote change stops you rather than getting silently overwritten.

RULE 3

Communicate Before Rewriting

When a shared branch genuinely must be rewritten, coordinate explicitly with everyone relying on it first, rather than surprising them.

RULE 4

Rotate, Don’t Just Rewrite

Treat any secret removed through history rewriting as still compromised, and issue a new credential rather than trusting the rewrite alone.

7Monitoring, Logging & Metrics

Because rebasing rewrites history, Git provides its own internal “logging” mechanism specifically for observing, tracking, and recovering from exactly this kind of operation.

The Reflog: Git’s Built-In Safety Net

Every time your local branch position changes for almost any reason — a commit, a checkout, and critically, a rebase — Git silently records that movement in a local log called the reference log, or reflog. This log isn’t shared with anyone else and isn’t part of your project’s real commit history; it’s a private, chronological record, kept only on your own machine, of everywhere your branches have pointed recently. Because interactive rebase moves your branch through a whole sequence of intermediate positions as it replays each commit, the reflog effectively becomes a step-by-step audit trail of the entire rebase, in order, including the exact position you started from before anything changed.

EVERYDAY ANALOGY

Think of a hiking app that quietly records your GPS position every few seconds, entirely separate from the trail map you’re following. Even if you take a wrong turn or the trail itself gets rerouted, that private tracking log still shows exactly where you actually walked, step by step — letting you retrace your path back to any earlier point, regardless of what the official map currently says.

Recovering “Lost” Commits After a Rebase

This is precisely why commits that seem to disappear after a rebase — dropped by mistake, or lost through an error — are very rarely gone for good. Because the reflog remembers exactly where your branch pointed immediately before the rebase began, you can look up that earlier position and point your branch back at it directly, instantly restoring the original, pre-rebase sequence of commits as though the rebase had never happened. Git also automatically keeps a special, easy-to-reach reference to your position right before certain operations, including a rebase, making this kind of recovery especially quick to perform without needing to search the full reflog by hand.

i
KEY TAKEAWAY

A botched interactive rebase is almost always recoverable, as long as you haven’t already deliberately deleted the reflog entries or let enough time pass that Git’s automatic housekeeping has cleaned them up. Checking the reflog should be the very first instinct whenever a rebase goes visibly wrong.

Tracking Progress During a Long Rebase

For a rebase spanning many commits, Git provides ongoing visibility into exactly where the process currently stands — which commit is being worked on, how many remain, and the full plan as originally saved — readable at any pause point, whether that pause was caused by an edit, a conflict, or simply checking in mid-process. Combined with the exec command described earlier, which can run an arbitrary command — most commonly a test suite — after each individual commit is replayed, a team can effectively build automated verification directly into the rebase itself, catching a commit that silently breaks something long before the rebase even finishes.

Why This Matters More at Scale

This kind of built-in observability becomes increasingly valuable as the size and complexity of a rebase grows. Cleaning up three or four commits rarely needs much tracking at all — the whole operation is over in moments, and any mistake is immediately obvious. Cleaning up thirty or forty commits accumulated over weeks of work on a long-running feature branch is a different matter entirely: a conflict discovered halfway through can be genuinely disorienting without a clear sense of exactly which commit triggered it and how many remain afterward. Teams working with unusually long-lived branches often treat the reflog and the exec-driven test-verification pattern described above not as optional conveniences but as a near-mandatory part of safely rebasing anything beyond a small, easily-reasoned-about handful of commits.

Reading the Resulting History as a Metric

After a rebase completes, the cleanliness of the resulting history is itself a useful, if informal, metric. A graphical view of recent commits — showing messages, authors, and the branching structure in a compact, readable form — is commonly used immediately after a significant rebase specifically to visually confirm the result looks exactly as intended: a straight line of well-scoped, clearly messaged commits, with no leftover experimental or duplicate entries.

sequenceDiagram
    participant B as Your Branch
    participant R as Reflog
    participant H as Repository History
    B->>R: Position recorded before rebase
    B->>H: Interactive rebase runs
    H-->>B: Branch now points to new commits
    Note over B,R: Something looks wrong
    B->>R: Look up pre-rebase position
    R-->>B: Return saved reference
    B->>H: Branch reset to that position
    H-->>B: Original history restored
    

Fig 2 — The reflog quietly preserves your branch’s pre-rebase position, making a mistaken rebase reversible on your own machine.

8Design Patterns & Anti-patterns

Teams that use interactive rebase well tend to converge on a small set of recurring, well-tested patterns — and there are equally well-known ways it goes wrong.

Proven Patterns

PATTERN

Commit Often, Clean Up Later

Make small, frequent, imperfect commits while actively working, trusting that interactive rebase will let you shape them into a clean sequence before anyone else needs to see them.

PATTERN

Autosquash Workflow

Create dedicated “fixup” commits explicitly linked to an earlier commit they correct, then let Git automatically reorder and mark them for folding during the next interactive rebase, removing manual reordering entirely.

PATTERN

Rebase Before Review, Not During

Clean up commit history once, right before opening a pull request, rather than repeatedly rewriting history mid-review, which can make it harder for reviewers to track what changed between their passes.

PATTERN

Test-Verified Rebase

Use the exec command to automatically run the test suite after every replayed commit, catching a commit that would otherwise silently leave the codebase broken partway through history.

Anti-patterns to Avoid

WATCH OUT FOR

  • Interactively rebasing a branch that teammates have already pulled and started building additional commits on top of
  • Force-pushing without first confirming no one else has pushed new work to that same branch in the meantime
  • Squashing an enormous number of unrelated commits into one giant, unreviewable commit purely to make history look short
  • Using interactive rebase to permanently erase evidence of a real mistake, rather than to genuinely improve clarity
  • Attempting a large, complex rebase with unresolved uncertainty about what each commit actually does, inviting avoidable conflicts
PATTERN-07 · Rebase vs. Merge for Combining Branches DECISION GUIDE
THE QUESTION

Should a feature branch be combined into the main branch using a merge, which preserves both histories and adds a merge commit, or a rebase, which replays the feature’s commits directly onto the main branch’s tip?

THE TRADE-OFF

A merge preserves the true, original timeline and is always safe on shared branches, since it never rewrites existing commits — but it can leave a more tangled, harder-to-read history. A rebase produces a clean, linear history but requires new commit hashes and carries the sharing risks covered in the Security chapter.

A COMMON RESOLUTION

Many teams split the difference: developers interactively rebase and clean up their own, still-private feature branch commits freely, then combine the finished, cleaned-up branch into the shared main branch using either a merge or a single squashed commit, keeping the risky, history-rewriting part of the workflow entirely confined to branches only one person owns.

9Best Practices & Common Mistakes

A distilled checklist for using interactive rebase confidently, without the anxiety it often causes newcomers.

7
CORE TODO-LIST
COMMANDS TO LEARN
1
SAFETY NET: THE
LOCAL REFLOG
0
SHARED BRANCHES SHOULD
EVER BE FORCE-REWRITTEN CASUALLY

Best Practices

  • Only rebase what you own. Treat any branch other people are already building on as off-limits for interactive rebase unless it’s been explicitly coordinated.
  • Make a safety branch before a risky rebase. Creating a quick backup pointer to your current position before a complex rebase costs seconds and removes nearly all anxiety about the outcome.
  • Read the whole todo list before saving. Understand every planned command in context before committing to the plan, rather than editing line by line without seeing the full picture.
  • Resolve conflicts calmly, one at a time. A paused rebase is not a failure state — it’s the normal, expected way Git asks for your judgment on genuinely ambiguous changes.
  • Verify the result before sharing. Look at the rewritten history and, ideally, rerun tests, before force-pushing anything to a remote.
  • Know how to abort. A rebase can always be cleanly canceled mid-process, instantly restoring your branch to exactly where it was before you started, no different from never having begun.

Common Mistakes

✕ Force-pushing rewritten history to a shared branch without checking whether teammates had already pushed new commits in the meantime.
✕ Panicking and assuming lost commits after a rebase are unrecoverable, without ever checking the local reflog first.
✕ Confusing squash with fixup, then being surprised that a “quick fix” commit’s message shows up combined into the final commit message unintentionally.
✕ Reordering commits without considering that changed order can introduce conflicts that never existed in the original sequence.
✕ Assuming removing a secret with an interactive rebase alone is sufficient, without also rotating the exposed credential.

10Real-World & Industry Examples

Seeing how real teams and projects actually apply interactive rebase makes its role in professional workflows concrete.

Open-Source Contribution Etiquette

Many well-established open-source projects explicitly ask contributors to clean up their commits with interactive rebase before a pull request will be reviewed, specifically requesting a small number of logically scoped, well-messaged commits rather than dozens of raw, in-progress ones. Maintainers reviewing hundreds of contributions rely heavily on this convention to keep the project’s permanent history readable for everyone who comes after.

Enterprise Code Review Standards

Inside larger engineering organizations, some teams adopt a strict linear-history policy, requiring every branch to be interactively rebased onto the latest main branch before merging, specifically to avoid the more tangled history that repeated ordinary merging tends to produce over time in a very active, high-traffic repository. Other teams intentionally choose the opposite policy, preferring merge commits precisely because they preserve an untouched, more literal record of when and how work actually combined.

Release Engineering and Cherry-Picking

Teams maintaining multiple release versions of a product simultaneously often use interactive rebase to prepare a small, targeted set of commits — extracted and cleaned from a much larger development branch — meant to be applied specifically to an older release branch, without bringing along unrelated changes that branch isn’t ready for.

Security Incident Response

When a credential is accidentally committed and discovered quickly, before it’s been widely shared or forked, some teams use a targeted interactive rebase with the edit command as a fast, surgical first step to strip the secret from history, immediately followed — without exception — by rotating that credential through the appropriate system, exactly as described in the Security chapter.

Educational and Onboarding Contexts

Because interactive rebase touches so many core Git concepts at once — commits, hashes, branches, conflicts, and the reflog — it’s frequently used deliberately as a teaching tool in engineering onboarding programs, precisely because understanding it well tends to deepen a new engineer’s understanding of how Git works internally far beyond the feature itself.

Automated Tooling Built Around Interactive Rebase

Beyond manual, one-off use, several categories of developer tooling are built directly on top of interactive rebase’s underlying mechanics. Graphical Git clients frequently offer a visual, drag-and-drop interface for reordering and combining commits that, internally, is simply generating and executing the same todo list a developer would otherwise edit by hand in a text editor. Automated code-quality bots on some platforms can suggest exact fixup commits for a pull request, designed to be folded in with a single autosquash rebase rather than requiring the contributor to manually edit history themselves. This widespread tooling support is itself a signal of how central the underlying concept has become to modern, professional software development, well beyond its origins as a purely manual, command-line technique.

“Interactive rebase is the closest thing Git offers to a time machine for your own recent work — powerful precisely because it lets you rewrite the past, and risky for exactly the same reason.”

11Frequently Asked Questions

Q1Is interactive rebase the same thing as GitHub’s “Rebase and merge” button?
No. GitHub’s “Rebase and merge” option performs an automatic, non-interactive rebase at merge time, replaying a pull request’s existing commits as-is onto the target branch with no todo list and no opportunity to reword, squash, or drop anything. True interactive rebase is a local Git operation, run in your own terminal or editor, that gives you full, line-by-line control before anything is shared.
Q2What happens if I make a mistake during an interactive rebase?
In most cases nothing is truly lost. A rebase in progress can be aborted cleanly at any point, instantly restoring your branch to its exact pre-rebase state. Even after a rebase completes, the local reflog retains a record of your previous position, letting you reset back to it if the result isn’t what you intended.
Q3What’s the real difference between squash and fixup?
Both combine a commit into the one above it in the todo list, producing a single resulting commit. Squash pauses and lets you edit or merge both commits’ messages together; fixup skips that pause entirely and silently keeps only the message from the commit above, discarding the folded-in commit’s own message.
Q4Is it safe to rebase a branch I’ve already pushed to GitHub?
It’s safe as long as you’re confident no one else has based any work on that pushed branch yet. If you’re the only person using it, rebasing and then force-pushing the update is a completely standard, low-risk workflow. If anyone else may have already pulled or built on top of it, coordinate with them first to avoid silently discarding their work.
Q5Why does Git pause and show me conflict markers during a rebase?
Because each commit is independently replayed against the current state of the code at that point in the sequence, a change that applied cleanly in the original history can occasionally fail to apply the same way against a different base or surrounding order. Git pauses at that exact point, showing you the conflicting sections so you can resolve them by hand before continuing.
Q6Can interactive rebase split one commit into several smaller ones?
Yes. Marking a commit with edit pauses the rebase right after that commit is applied, leaving you free to partially undo it, then create several smaller, more focused commits from its contents before resuming the rest of the rebase as planned.

12Summary and Key Takeaways

Interactive rebase gives you deliberate, line-by-line control over how a sequence of your own commits gets rewritten before it becomes a permanent part of shared history. Internally, it works by building an editable plan, detaching from your branch, and carefully replaying each commit according to your instructions — reworded, combined, split, reordered, or dropped as needed — before pointing your branch at the freshly built result. That power comes from a simple, honest trade: every rebased commit is a genuinely new object with a new identity, which is exactly why sharing rebased history safely requires real care, coordination, and — ideally — a healthy respect for the reflog as your local safety net whenever something doesn’t go as planned.

Key Takeaways

  • Definition: interactive rebase pauses an ordinary rebase to let you edit an explicit todo list, controlling exactly how each commit in a sequence is rewritten before it’s replayed.
  • Command vocabulary: pick, reword, edit, squash, fixup, drop, and exec cover the full range of what can be done to each commit in the plan.
  • New commits, not edited ones: because a commit’s hash depends on its parent, every rebased commit is a brand-new object, even when its content looks unchanged.
  • Reflog is the safety net: Git’s local reference log quietly preserves your pre-rebase position, making most rebase mistakes fully recoverable on your own machine.
  • Sharing requires care: rewritten history needs a force push to share, which is safe on branches you alone own and genuinely risky on branches others are actively building on.
  • Distinct from GitHub’s automatic rebase: GitHub’s “Rebase and merge” button performs a non-interactive replay at merge time, with none of the editable control true interactive rebase offers locally.
  • A tool for clarity, used deliberately: mature teams commit freely and imperfectly during development, then rely on interactive rebase, applied thoughtfully and only to their own commits, to shape that work into clean, reviewable, permanent history.