GitHandling Rebase Conflicts

Handling Rebase Conflicts

Rebases can produce conflicts just like merges — but with a twist: each replayed commit can conflict separately, so a long rebase might pause several times. The resolution procedure is the same as merge conflicts, with one confusing difference: --ours and --theirs mean the opposite of what you’d expect.

What happens during a rebase conflict

A typical conflict mid-rebase

Bash
git switch feature-x
git rebase main
# CONFLICT (content): Merge conflict in src/app.js
# error: could not apply 1f9ab2c... Add login form
# Resolve all conflicts manually, mark them as resolved with
# "git add <conflicted_files>", then run "git rebase --continue".
The resolution recipe
  • Run git status to see which files conflict.

  • Open each file, resolve the conflict (delete markers).

  • git add <file> to mark each one resolved.

  • git rebase --continue to replay the next commit.

  • Repeat until rebase finishes.

Step by step

Bash
# 1. See conflicts
git status

# 2. Edit each conflicted file in your editor

# 3. Stage the resolutions
git add src/app.js

# 4. Continue to the next commit
git rebase --continue
The big gotcha: --ours and --theirs are flipped
Why are they reversed during rebase?
During a rebase, Git pretends you started from the base branch (here `main`) and is REPLAYING your commits on top. From Git’s point of view, the base branch is “ours” (the branch we’re building on) and YOUR commits are “theirs” (incoming).
  • --ours during a rebase = the branch you are rebasing onto (usually main).

  • --theirs during a rebase = your branch (the commits being replayed).

Picking one side

Bash
# Take main's version
git checkout --ours -- src/app.js

# Take YOUR feature branch's version
git checkout --theirs -- src/app.js

git add src/app.js
git rebase --continue
Skipping a commit

If a commit is redundant (e.g. the same change is already in main)

Bash
git rebase --skip
# Drops the current commit and continues with the next one
Aborting

Bash
git rebase --abort
# Cancels the rebase, restores feature-x to its pre-rebase state
Several conflicts in a row

Long rebases can hit conflicts multiple times — once per replayed commit. The loop is always: resolve → git addgit rebase --continue → next conflict (or done).

A 3-conflict rebase

Bash
git rebase main
# CONFLICT in src/a.js   ← commit 1 of 3 conflicts here

# Resolve, then:
git add src/a.js
git rebase --continue
# CONFLICT in src/b.js   ← commit 2 of 3 conflicts here

git add src/b.js
git rebase --continue
# CONFLICT in src/c.js   ← commit 3 of 3 conflicts here

git add src/c.js
git rebase --continue
# Successfully rebased and updated refs/heads/feature-x.
Re-using resolutions: rerere

Enable Git to remember

Bash
git config --global rerere.enabled true

With rerere (reuse recorded resolution), Git stores how you resolved a conflict. The next time the same conflict appears — common during repeated rebases — Git applies your previous resolution automatically. This is a huge time-saver on long-lived branches.

Reducing conflicts before they happen
  • Short-lived branches. Merge or rebase frequently; fewer divergent commits mean fewer conflicts.

  • Pull --rebase often. git pull --rebase keeps your branch on top of the latest base, surfacing conflicts in small batches.

  • Split big rebases. Instead of rebasing 20 commits at once, do them in 5-commit chunks.

  • Communicate. When you and a teammate work on the same files, coordinate so one of you merges first.

Recovering after a bad rebase

The reflog is your friend

Bash
git reflog
# 1f9ab2c HEAD@{0}: rebase finished: ...
# d4b1e0c HEAD@{1}: rebase in progress: ...
# c204c1d HEAD@{2}: rebase start: ...
# a3b2c1d HEAD@{3}: checkout: ...      ← pre-rebase state!

git reset --hard HEAD@{3}
# Back to where you were before the rebase
Tip
After resolving a rebase conflict, run tests on the intermediate commit before continuing. A conflict can leave a commit broken even if it compiles — and you’ll thank yourself for catching it now instead of at the end of a long rebase.