Git Rebase Conflict: How to Resolve (Tested)

A git rebase conflict happens when the commit git is replaying changes a line that the branch you're rebasing onto already changed differently. git marks the spot in the file with <<<<<<<, =======, and >>>>>>> — the same three markers a merge conflict uses, but labeled differently. We reproduced one from scratch and recorded exactly what git prints and writes.

1. How we reproduced it

We made one file, committed it, then branched and edited the same line differently on main and on feature before rebasing feature onto main.

git init -b main
git config user.email "test@example.com"
git config user.name "Test User"
printf "line1\nline2\nline3\n" > file.txt
git add file.txt
git commit -m "base commit"

git checkout -b feature
printf "line1\nFEATURE-CHANGE\nline3\n" > file.txt
git commit -am "feature: change line2"

git checkout main
printf "line1\nMAIN-CHANGE\nline3\n" > file.txt
git commit -am "main: change line2"

git checkout feature
git rebase main

git rebase main printed exactly:

Rebasing (1/1)Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
error: could not apply 286b0aa... feature: change line2
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config advice.mergeConflict false"
Could not apply 286b0aa... feature: change line2

git rebase exited with status 1.

2. The markers look different from a merge conflict — here's exactly how

Here is the full content of file.txt after the conflicting rebase, byte for byte:

line1
<<<<<<< HEAD
MAIN-CHANGE
=======
FEATURE-CHANGE
>>>>>>> 286b0aa (feature: change line2)
line3

We ran the exact same two-line conflict through git merge instead, for comparison. Its markers:

line1
<<<<<<< HEAD
MAIN-CHANGE
=======
FEATURE-CHANGE
>>>>>>> feature
line3

The opening <<<<<<< HEAD line looks identical, but it means something different in each case:

That's the one thing worth remembering: a merge's closing marker names a branch; a rebase's closing marker names the specific commit (hash + message) currently being replayed, because a multi-commit rebase can conflict on each commit in turn with a different hash each time.

3. What git status says during a rebase conflict

We ran git status while the conflict was open. Exact output:

interactive rebase in progress; onto a267195
Last command done (1 command done):
   pick 286b0aa feature: change line2
No commands remaining.
You are currently rebasing branch 'feature' on 'a267195'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   file.txt

no changes added to commit (use "git add" and/or "git commit -a")

Note it says "interactive rebase in progress" even though we ran a plain, non-interactive git rebase main — git 2.47.3 uses the same sequencer-based machinery for both, so the message is identical either way. The both modified line is the same wording a merge conflict uses.

4. Is this a "detached HEAD"? Yes, but git tells you exactly what's going on

We checked directly: during the conflict, git branch --show-current printed nothing, and git symbolic-ref HEAD failed with fatal: ref HEAD is not a symbolic ref (exit 128). .git/HEAD held a raw commit SHA, not a ref name. Mechanically that is the same detached HEAD state you get from checking out a commit directly.

The difference is what git tells you. A plain detached checkout's git status just says HEAD detached at <sha> with generic advice. Mid-rebase, git status instead says "You are currently rebasing branch 'feature' on '<sha>'" and gives rebase-specific next steps (--continue/--skip/--abort). You're detached either way, but a rebase in progress is self-documenting, so you don't need to recognize detached HEAD yourself to know how to get out.

5. Resolving it: edit, add, --continue

We edited the file to the content we wanted, removing all three marker lines ourselves (git does not do this for you):

printf "line1\nRESOLVED-LINE\nline3\n" > file.txt
git add file.txt
git rebase --continue

Exact output:

[detached HEAD 6a7763d] feature: change line2
 1 file changed, 1 insertion(+), 1 deletion(-)
Successfully rebased and updated refs/heads/feature.

Exit code was 0. Git itself labels the intermediate commit [detached HEAD ...], confirming the state from section 4. The resulting commit has a new hash (6a7763d, not the original fa34f88) because rebase rewrites every commit it replays. git log --oneline afterward showed a clean, linear history: feature's commit now sits directly on top of main's, with no merge commit.

6. git rebase --skip: drops the commit entirely

Instead of resolving, we ran git rebase --skip on the same conflict. Exact output:

Successfully rebased and updated refs/heads/feature.

Exit code 0 — but the conflicting commit's change is simply discarded, not applied in any form. git log afterward no longer contained the feature: change line2 commit at all, and file.txt matched main's version exactly (MAIN-CHANGE), with no trace of FEATURE-CHANGE anywhere. Use --skip only when you're sure that commit's change is no longer needed; there's no silent recovery of it afterward other than finding the original commit hash via git reflog.

7. git rebase --abort: full rollback

We also triggered the conflict and ran git rebase --abort instead. Exit code 0, no other output. git status immediately showed On branch feature / nothing to commit, working tree clean, git branch --show-current printed feature again (HEAD reattached), and git log --oneline showed the branch's single original commit, unchanged. --abort is a complete, exact restore to the state right before the rebase started — unlike --skip, nothing is lost.

8. Quick comparison

CommandExit codeResult
git rebase --abort0Full rollback. Branch and history exactly as before the rebase.
git rebase --skip0The conflicting commit's change is dropped entirely. History continues without it.
Resolve + git add + git rebase --continue0A new commit (new hash) with your resolved content, rebase continues linearly.

Quick checklist: run git status to see which command you're mid-rebase and which file is both modified; open it, delete the <<<<<<</=======/>>>>>>> markers by hand after picking the content you want; git add each resolved file; then git rebase --continue. Changed your mind entirely? git rebase --abort restores the pre-rebase state exactly.

Frequently asked questions

How is a git rebase conflict different from a merge conflict?

The three markers (<<<<<<<, =======, >>>>>>>) are identical, but the closing label differs. We measured it: a merge's >>>>>>> marker names the branch being merged in (>>>>>>> feature); a rebase's >>>>>>> marker names the abbreviated hash and subject of the specific commit being replayed (>>>>>>> 286b0aa (feature: change line2)), since a multi-commit rebase can conflict on a different commit each time.

Does a rebase conflict put me in detached HEAD?

Yes, mechanically. We confirmed git branch --show-current printed nothing and .git/HEAD held a raw commit SHA during the conflict, same as a plain detached checkout. But git status's wording is rebase-specific ("You are currently rebasing branch 'feature' on '<sha>'") rather than the generic "HEAD detached at <sha>" message, and it hands you the exact --continue/--skip/--abort options.

What's the difference between git rebase --skip and --abort?

We tested both. --abort fully restores the branch and history to exactly how they were before the rebase started, with the original commit intact. --skip instead discards the conflicting commit's change completely and continues the rebase without it; that change does not reappear later.

Does git rebase --continue create a new commit?

Yes. In our test the resolved commit got a new hash (6a7763d) different from the original (fa34f88), because rebase always rewrites the commits it replays. git itself labeled the intermediate state [detached HEAD 6a7763d] in its own output before printing "Successfully rebased and updated refs/heads/feature."

Why does git status say "interactive rebase in progress" when I ran a plain git rebase?

We saw this exact wording after a plain, non-interactive git rebase main on git 2.47.3. Git uses the same sequencer-based backend for both interactive and non-interactive rebases internally, so the status message doesn't distinguish them.

Written with AI assistance. Measured on 2026-10-03 with git 2.47.3 on Linux, plain CLI only (no GUI tool), in disposable /tmp repos. PlainHeaders is our extension; git is free and open source.