Git

Git Interactive Rebase Keeping Empty or Duplicate Commits

· by DebuggedIt

Quick answer

Empty or duplicate commits appearing after an interactive rebase usually comes down to one of two specific, well-understood situations: a commit whose changes...

Empty or duplicate commits appearing after an interactive rebase usually comes down to one of two specific, well-understood situations: a commit whose changes were already applied elsewhere becoming genuinely empty during the rebase, or a commit that Git doesn't correctly recognize as a duplicate of one already present on the target branch, causing it to be reapplied rather than skipped.

The Problem

After an interactive rebase, the resulting history includes commits that either have no actual changes, or that duplicate changes already present elsewhere in the history:

git log --oneline
a1b2c3d Fix typo in README
e4f5g6h Fix typo in README   # duplicate, same change appears twice

Or, separately:

git show a1b2c3d
# shows a commit with no actual diff content, despite having a message and existing in history

Why It Happens

Two genuinely distinct mechanisms produce these two different symptoms:

  • Empty commits occur when a commit's changes, once applied during the rebase, result in no actual difference from the current state — this happens when the same change was already applied by an earlier commit in the rebase sequence, or already exists on the branch you're rebasing onto, so reapplying it produces literally nothing new to commit
  • Duplicate commits occur when Git's rebase doesn't recognize that a commit's changes are equivalent to one already present in the target branch's history (often because the commit hash differs, even if the actual resulting change is identical — for example, after a previous cherry-pick or an earlier rebase already applied the same logical change under a different commit hash), causing the same logical change to be reapplied and appear twice in the resulting history

The Fix

For empty commits specifically, Git's default rebase behavior in recent versions typically drops truly empty commits automatically — but if you're seeing them retained, you can explicitly control this behavior:

# Explicitly drop empty commits during rebase
git rebase --empty=drop origin/main

# Or explicitly keep them, if that's genuinely intended for some reason
git rebase --empty=keep origin/main

If you're in the middle of an interactive rebase and encounter an empty commit that rebase has paused on (asking whether to skip or keep it), you can decide in the moment based on whether the emptiness is expected:

# If you confirm the commit is genuinely, correctly empty (its change is already applied)
git rebase --skip

# If you believe it shouldn't be empty and something's wrong, investigate before continuing
git status
git diff

For duplicate commits, the underlying cause is usually that Git's rebase couldn't recognize the equivalence between commits with different hashes but the same effective change — using git rebase with the --onto flag and carefully specifying the correct base commit, rather than a potentially ambiguous relative reference, often avoids this by making the intended rebase scope more precise:

git rebase --onto origin/main <last-commit-before-your-changes> your-branch

If duplicates have already been created and are now part of your history, the direct fix is an additional interactive rebase specifically to remove the redundant commit(s):

git rebase -i origin/main

In the interactive rebase editor, delete the line corresponding to the duplicate commit entirely (rather than marking it pick), which removes it from the resulting history while keeping every other commit intact:

pick a1b2c3d Fix typo in README
# delete this line entirely: pick e4f5g6h Fix typo in README
pick i7j8k9l Add new feature

Before starting a rebase where duplicate commits are a known risk (for example, rebasing a branch that's previously been partially cherry-picked onto the target), consider using git rebase with the --fork-point option, which attempts a more careful determination of the actual common ancestor, sometimes avoiding duplicate reapplication in scenarios involving prior reflog-tracked branch operations:

git rebase --fork-point origin/main

Still Not Working?

If duplicates keep recurring across multiple rebase attempts on the same branch, consider whether the branch's history has become genuinely tangled enough (through multiple previous rebases, cherry-picks, and merges) that a cleaner approach — creating a fresh branch and manually cherry-picking only the specific, genuinely-needed unique commits onto it, explicitly reviewing each one — is more reliable than continuing to rely on automatic rebase logic to correctly untangle an increasingly complex history on its own. This is more manual and time-consuming, but for a sufficiently tangled branch history, it can be more reliable than repeatedly troubleshooting automatic rebase behavior against a history that's accumulated enough complexity to routinely trip up the automatic duplicate-detection logic.