Superseding a branch with the ours strategy Jump to heading

Sometimes you need Git to believe a branch has been merged without taking any of its content. An old release branch whose fixes were all re-implemented differently on main. An experimental rewrite that was abandoned but whose history should stay reachable. A vendor branch replaced wholesale. Merging those branches normally would drag in changes you do not want; leaving them unmerged means every future comparison and every forward-merge reports them as outstanding. The ours merge strategy, git merge -s ours, creates a merge commit whose tree is exactly your current tree, recording the other branch as merged and ignoring its content entirely. It is easy to confuse with the -X ours option, which does something quite different. This page explains both, within merge strategies and gitattributes.

When to use this approach Jump to heading

  • A branch’s changes have been superseded and you want history to show it as merged.
  • Forward-merges from an old release branch into main keep proposing changes main deliberately does not want.
  • You are retiring a long-lived branch and want its commits reachable from main for reference.
  • You are not trying to resolve conflicts in your favour — for that, see Step 2 and ours and theirs during merge vs rebase.

Step 1 — Create a merge that keeps only your tree Jump to heading

Run the merge with the ours strategy from the branch that should survive. The resulting commit has two parents, but its tree is identical to the first parent’s.

git switch main
git merge -s ours --no-edit release/1.x -m "Mark release/1.x as superseded by main (no changes taken)"
git diff HEAD^1 HEAD --stat          # empty: nothing from release/1.x entered main
git log --oneline -1 --format='%h %p %s'
A merge that records history but takes no contentMain and an old release branch diverged long ago. The ours-strategy merge M has both as parents, so the release branch's commits become ancestors of main, but M's tree is exactly main's previous tree, so none of the release branch's changes appear.git merge -s ours release/1.xmainAM1M2Mrelease/1.xAR1R2tree of M= M2after M, git branch --merged main lists release/1.x A merge that records history but takes no contentMain and an old release branch diverged long ago. The ours-strategy merge M has both as parents, so the release branch's commits become ancestors of main, but M's tree is exactly main's previous tree, so none of the release branch's changes appear.git merge -s ours release/1.xmainAM1M2Mrelease/1.xAR1R2tree of M= M2after M, git branch --merged main lists release/1.x
# Verification: the branch now counts as merged
git branch --merged main | grep release/1.x
git log --oneline main..release/1.x | wc -l          # 0: nothing outstanding

Step 2 — Do not confuse -s ours with -X ours Jump to heading

The names are almost identical; the behaviour is not. -s ours is a whole strategy that ignores the other branch completely. -X ours is an option to the normal strategy: it merges everything as usual, and only where a hunk conflicts does it pick your side. Non-conflicting changes from the other branch are still taken.

-s ours against -X oursThe ours strategy produces a merge whose content is exactly the current branch, discarding every change from the other branch. The ours option to the default strategy merges normally and only resolves conflicting hunks in favour of the current branch, so the other branch's non-conflicting changes are kept.git merge -s oursgit merge -X oursother branch's clean changesdiscardedkeptconflicting hunksn/a — all discardedyour side winsresulting tree= your branchreal mergetypical usesupersede a branchbulk-resolve conflicts-s ours throws away everything; -X ours throws away only the other side of conflicts -s ours against -X oursThe ours strategy produces a merge whose content is exactly the current branch, discarding every change from the other branch. The ours option to the default strategy merges normally and only resolves conflicting hunks in favour of the current branch, so the other branch's non-conflicting changes are kept.git merge -s oursgit merge -X oursother branch's clean changesdiscardedkeptconflicting hunksn/a — all discardedyour side winsresulting tree= your branchreal mergetypical usesupersede a branchbulk-resolve conflicts-s ours throws away everything; -X ours throws away only the other side of conflicts
# -X ours: a real merge that auto-resolves conflicts toward HEAD
git merge -X ours feature/x
git diff HEAD^1 HEAD --stat          # not empty: feature/x's non-conflicting changes arrived

There is no -s theirs strategy. If you want a merge whose tree equals the other branch, the usual approach is to do an ours merge from the other side and then fast-forward, or to use git read-tree as shown in the FAQ.

Step 3 — Check that nothing was lost before you supersede Jump to heading

An ours merge declares the branch’s changes unwanted forever. Before running it, confirm every fix on the branch either exists on main in some form or is truly unneeded. Patch-ID comparison catches exact equivalents; anything left needs a human decision.

git cherry -v main release/1.x | grep '^+'        # commits on release/1.x with no equivalent on main

For each listed commit, decide whether main already has the fix in a different form, whether it should be ported now, or whether it is irrelevant. The fuller approach is in finding unported commits with git cherry.

⚠️ SAFETY WARNING: After an ours merge, Git considers every commit on the superseded branch merged. Any fix you overlooked will never be proposed again by a merge — later merges of that branch bring in only commits made after the ours merge. Run the git cherry check first. If you merged too early, revert the ours merge with git revert -m 1 <merge>; the branch’s commits become unmerged again in effect, and you can merge properly.

Step 4 — Use it to stop forward-merges proposing unwanted changes Jump to heading

Teams that merge release branches forward into main sometimes have a release-only change — a version pin, a branch-specific configuration — that must never reach main. Merging it forward with -s ours records it as handled, so future forward-merges skip it.

git switch release/2.4
git commit -am "Pin payment SDK to 3.1 for 2.4 only"       # release-only change
git switch main
git merge -s ours release/2.4 -m "Forward-merge release/2.4: skip release-only SDK pin"
# Later fixes on release/2.4 forward-merge normally

This only works if the release-only change is merged on its own, before any other unmerged release commits. If other fixes are also waiting, merge those normally first, then record the release-only commit with an ours merge.

Skipping a release-only commit in forward-mergesFixes on the release branch forward-merge into main normally. A release-only version pin is merged with the ours strategy, so main records it without taking it. Later fixes then forward-merge normally, and the pin is never proposed again.Fix Aforward-merged normallyMonSDK pinrelease-only commitTuemerge -s oursrecorded, not takenTueFix Bforward-merged normallyThuorder matters: merge real fixes first, then the ours merge for the release-only change Skipping a release-only commit in forward-mergesFixes on the release branch forward-merge into main normally. A release-only version pin is merged with the ours strategy, so main records it without taking it. Later fixes then forward-merge normally, and the pin is never proposed again.Fix Aforward-merged normallyMonSDK pinrelease-only commitTuemerge -s oursrecorded, not takenTueFix Bforward-merged normallyThuorder matters: merge real fixes first, then the ours merge for the release-only change

Validation checklist Jump to heading

Frequently Asked Questions Jump to heading

How do I make a merge that takes the other branch’s tree entirely? Jump to heading

Merge with -s ours from the other branch’s perspective on a temporary branch, or create the merge and then replace its tree: git merge -s ours --no-commit other && git read-tree -m -u other && git commit. Both produce a merge whose content equals other.

Does an ours merge affect git log? Jump to heading

The superseded branch’s commits appear in git log main, because they are now ancestors. Use --first-parent to view main’s own history without them.

Is this the same as deleting the branch? Jump to heading

No. Deleting the branch removes its name, and its commits eventually become unreachable. An ours merge keeps them reachable from main permanently while ensuring none of their changes apply.