Ours and theirs during merge vs rebase Jump to heading

git checkout --ours file during a merge keeps your branch’s version. Run the same command during a rebase and it keeps the other branch’s version — the one you are rebasing onto — discarding your own change. This is not a bug; it follows directly from how rebase works. But it catches nearly everyone at least once, usually while resolving a large conflict quickly and confidently picking “ours” everywhere. The same swap affects conflict markers, the -X ours strategy option and merge tool pane labels. This page explains the mechanics once, so the swap stops being surprising, and gives a few habits that remove the need to remember. It belongs to 3-way merge fundamentals.

When to use this approach Jump to heading

  • You resolve conflicts during both merges and rebases.
  • You use checkout --ours/--theirs or -X ours/theirs to resolve conflicts in bulk.
  • A rebase resolution once threw away your own changes and you were not sure why.
  • You use rebase-based workflows such as configuring git pull --rebase safely for a team.

Step 1 — Understand what “ours” means in each operation Jump to heading

“Ours” always means the commit that HEAD points to while the conflict is being resolved. The difference between merge and rebase is what HEAD is at that moment.

What ours and theirs refer toDuring a merge, HEAD is your branch and the incoming branch is theirs. During a rebase, Git first checks out the branch you are rebasing onto and replays your commits on top, so HEAD is the upstream and the commit being replayed — your own work — is theirs.ours (HEAD)theirsgit merge featureyour branchfeaturegit rebase mainmain + replayed so faryour commitgit cherry-pick Xyour branchcommit Xgit revert Xyour branchinverse of Xrebase is the odd one out because it moves HEAD to the other branch first

A rebase is a series of cherry-picks onto the target branch. Git checks out the target, then applies your commits one at a time. While applying each one, HEAD is the target plus whatever has been replayed so far, so “ours” is the target branch and “theirs” is the commit being replayed — yours.

# Verification: during a stopped rebase, HEAD is not your branch
git rebase main          # stops on a conflict
git rev-parse --abbrev-ref HEAD      # prints HEAD (detached), not your branch name
git log -1 --format='%h %s' HEAD     # the last commit on main or the last replayed commit
cat .git/rebase-merge/stopped-sha 2>/dev/null   # the commit of yours being applied

Step 2 — Apply it to checkout --ours and --theirs Jump to heading

The flags pick a whole-file version from the index stages. Stage 2 is ours and stage 3 is theirs, whatever the operation.

# During a MERGE of feature into your branch:
git checkout --ours   path   # keep your branch's version
git checkout --theirs path   # take feature's version

# During a REBASE of your branch onto main:
git checkout --ours   path   # take main's version (discards your change to this file)
git checkout --theirs path   # keep your commit's version
Which flag keeps my change?In a merge, --ours keeps your branch's version of a file. In a rebase or when popping a stash over a dirty change, --theirs keeps your own change, because your work is the thing being applied on top of HEAD.Which operation stopped on the conflict?merge--ourskeeps your branchrebase--theirskeeps your commitcherry-pick--theirskeeps the picked commitrule of thumb: whatever is being applied on top is theirs

The same applies to the strategy options. git rebase -X theirs main resolves every conflicting hunk in favour of your commits; -X ours in favour of main. Using -X ours in a rebase “to keep my changes” does the exact opposite.

Step 3 — Read conflict markers by label, not by position Jump to heading

Conflict markers label each side. During a merge the top section is labelled HEAD and the bottom with the incoming branch name. During a rebase the top is labelled with the upstream commit and the bottom with your commit’s subject.

<<<<<<< HEAD
timeout = 30
||||||| parent of 7c1e2a9 (Raise API timeout for slow regions)
timeout = 20
=======
timeout = 45
>>>>>>> 7c1e2a9 (Raise API timeout for slow regions)

That bottom label is your commit. With zdiff3 the base label also names it (“parent of 7c1e2a9”), which makes the situation unambiguous: the bottom section is the change you made, and the top section is what main has now. Turning on ancestor-style markers, described in reading diff3 and zdiff3 conflict markers, is the single best fix for ours/theirs confusion.

Step 4 — Use explicit refs instead of ours and theirs Jump to heading

When in doubt, avoid the words entirely. Take a file’s version from a named commit, which reads the same in every operation.

# During a rebase: take your commit's version explicitly
git checkout "$(cat .git/rebase-merge/stopped-sha)" -- path/to/file

# During a merge: take a named branch's version
git checkout feature/x -- path/to/file

# Or take main's version explicitly, in any operation
git checkout main -- path/to/file
A guess-free resolution habitWhen a conflict stops an operation, first identify HEAD and the commit being applied, then resolve each file by naming the commit whose version you want, and finally check the staged diff to confirm your own change survived.Identify HEADgit log -1 HEADIdentify appliedstopped-sha / MERGE_HEADPick by namecheckout <ref> -- pathVerifydiff --cachednaming the commit you want is never ambiguous, whatever the operation

Checking out a whole file from one side discards the other side’s changes to that file entirely, not just the conflicting hunks. Prefer it only for files where one side’s version is clearly correct, such as generated files.

# Verification: your change is still present after resolving
git diff --cached -- path/to/file

Step 5 — Recover when you picked the wrong side Jump to heading

If you resolved with the wrong flag and continued, the discarded version is not lost. During a rebase, your original commits remain in the reflog; after a merge, the other side is still a parent of the merge commit.

# Rebase: find your branch's state before the rebase began
git reflog show --date=relative "$(git branch --show-current)" | head -5
git diff ORIG_HEAD HEAD -- path/to/file      # what the rebase changed in this file

# Restore the file from your pre-rebase branch and amend
git checkout ORIG_HEAD -- path/to/file && git commit --amend --no-edit

⚠️ SAFETY WARNING: ORIG_HEAD is overwritten by the next operation that sets it — another rebase, a reset, a merge. If you are not recovering immediately, use the reflog entry instead (branch@{1} or the hash from git reflog), which stays available for ninety days by default.

Validation checklist Jump to heading

Frequently Asked Questions Jump to heading

Why didn’t Git just swap the meanings for rebase to make them intuitive? Jump to heading

Because “ours” is defined as HEAD in all operations, which keeps the low-level machinery consistent. Rebase is implemented as repeated cherry-picks onto the upstream, so HEAD is the upstream. Changing that would make the plumbing inconsistent.

Does the same swap apply to git pull --rebase? Jump to heading

Yes. pull --rebase fetches and then rebases your local commits onto the updated upstream, so during its conflicts your local commits are “theirs”.

What about stash pop? Jump to heading

When applying a stash, HEAD is your current branch and the stash is being applied on top, so the stash is “theirs”. Conflicts from popping a stash are covered in resolving conflicts when popping a stash.