skip to content

During a git rebase conflict, which side is "ours" and which is "theirs", and why?

level: middleimportance: must knowfreq 60%

answer

  1. It depends on what is checked out
  2. Rebase moves you to the new base first
  3. Each commit is applied like a cherry-pick
  4. Reaching for --theirs keeps your own work
  5. Read the closing marker label, do not assume

basics

~20 s

They are inverted relative to a merge. During a rebase, ours is the branch you are replaying onto — the new base plus commits already applied — and theirs is the commit from your own branch currently being replayed.

solid answer

~50 s

In a merge the labels match intuition: `ours` is the branch you have checked out, `theirs` is the branch being merged in. A rebase inverts that, because of how rebase works mechanically. `git rebase upstream` first moves HEAD to the upstream tip, then replays each of your commits onto it as a cherry-pick. At any moment, the checked-out side — the *current* state — is the new base plus whatever has already been replayed. That is `ours`. The patch being applied on top is `theirs`, and that patch comes from **your** branch. So during a rebase, `git checkout --ours <file>` gives you the upstream version and `--theirs` gives you your own work — the opposite of what most people reach for. The conflict markers hint at this: the `HEAD` side is the upstream state, and the closing label names the commit being replayed.

go deeper

for a junior

Remember the headline: during a rebase the two labels are the opposite of what you expect, so check before grabbing a whole side. Resolving by editing the file avoids the trap entirely.

for a middle

Derive the inversion rather than memorising it: ours is whatever is checked out, and rebase checks out the new base before replaying your commits as cherry-picks. Explain why that also means one stop per commit.

for a senior

Demonstrate the habits that keep a long rebase safe — reading marker labels, aborting rather than guessing, and recognising when repeated identical conflicts mean the branch has drifted too far to keep replaying.

for a principal

Own the consequence at team scale: the inversion is a recurring source of silently lost work, so decide where rebasing is worth its hazard and what conventions or defaults reduce the blast radius.

## The rule, stated precisely `ours` always means *the side that is currently checked out*, and `theirs` always means *the side whose changes are being applied to it*. That single definition never changes. What changes is which of your two branches occupies which role. In a merge on `feature`, HEAD is `feature`, so `ours` is `feature` and `theirs` is `main`. In `git rebase main` while on `feature`, Git first checks out `main`'s tip (detached), then applies your `feature` commits one at a time on top of it. HEAD is therefore on the *upstream* side, so `ours` is `main` plus already-replayed commits, and `theirs` is the `feature` commit currently being replayed. The labels have not flipped meaning; your branches have swapped seats. ## Why rebase works that way Rebase does not move commits; it re-creates them. To re-create a commit on a new base, Git must first *be* on that new base, then apply the commit's change as a patch. That is a cherry-pick, and a cherry-pick's three-way merge treats the commit's parent as the base, the commit as the incoming change, and the current HEAD as ours. Every rebase is a sequence of these, which is also why a rebase can stop on a conflict once per commit rather than once for the whole operation. ## Concrete consequences - `git checkout --ours <file>` during a rebase discards **your** changes to that file and keeps the upstream version. `--theirs` keeps your version. This is the single most common way people destroy their own work mid-rebase. - The conflict-marker labels reflect the same inversion: the block labelled `HEAD` is the upstream-plus-replayed state, and the closing label carries the hash and subject of *your* commit being replayed. Reading those labels rather than assuming is the reliable habit. - Strategy options that favour one side follow the same seat assignment, so a preference you would express one way in a merge must be expressed the other way in a rebase. ## How to keep it straight under pressure Three checks work without memorising anything: 1. Ask what is checked out right now. During a rebase, HEAD is on the new base. Whatever HEAD is, that is `ours`. 2. Read the marker labels. The closing `>>>>>>>` label names a commit; if that commit is one of yours, you are in a rebase and your work is the `theirs` side. 3. Prefer resolving by editing the file to the content you want rather than by grabbing a whole side. Editing is side-agnostic and immune to the inversion. ## Why the inversion feels wrong The emotional model is "I am rebasing *my* branch, so my branch is ours." The mechanical model is "Git is currently sitting on the new base, applying patches from elsewhere." The words follow the mechanics, not the intent. Once you internalise that rebase means *replay my commits somewhere else*, the seating becomes obvious: to replay them somewhere else, you first have to go there. ## The same inversion elsewhere Because the rule is about what is checked out, anything built on cherry-pick shows the same behaviour. Applying someone else's patch onto your branch makes your branch `ours` and the patch `theirs` — which reads naturally. It is specifically the case where the incoming patch is *your own commit* that surprises people, and that is exactly the rebase case. ## Practical safety Mid-rebase state is fully recoverable: `git rebase --abort` restores the branch to where it started. If you suspect you resolved a hunk by grabbing the wrong side, aborting and restarting is cheap and far safer than trying to reconstruct the lost lines afterwards. If the same conflicts recur every time you rebase a long-lived branch, recording resolutions so Git can replay them saves the repeated decision — but only after you have made the decision correctly once.

  • Why does a rebase stop once per commit while a merge stops at most once?
    A merge computes a single three-way result between two tips. A rebase re-creates each commit in turn, and every one of those applications is its own three-way merge against the evolving base. So a ten-commit rebase can present up to ten separate conflict stops, each about that one commit's patch.
  • During a rebase, how can you tell from the file alone which side is yours?
    Read the marker labels. The block opened by <<<<<<< is labelled HEAD and holds the upstream-plus-replayed state; the closing >>>>>>> line names the commit being replayed, including its hash and subject. If that subject is one of your commits, the lower block is your work.
  • If you resolved several hunks the wrong way round mid-rebase, what is the cheapest recovery?
    `git rebase --abort`, which returns the branch to its pre-rebase tip and discards the partial replay. Restarting costs only the resolutions you had already made; trying to reconstruct silently discarded lines from a wrong-side resolution is slower and much less reliable.

saying these in an interview costs you the question

  • Says ours always means my feature branch
  • Uses checkout --ours to keep own work during a rebase
  • Thinks the labels flip meaning during a rebase
  • Believes a rebase conflicts once for the whole operation
  • Cannot explain why HEAD is on the upstream side

context