ChatGPT解决这个技术问题 Extra ChatGPT

What is the precise meaning of "ours" and "theirs" in git?

This might sound like too basic of a question, but I have searched for answers and I am more confused now than before.

What does "ours" and "theirs" mean in git when merging my branch into my other branch? Both branches are "ours".

In a merge conflict is "ours" always the upper of the two versions displayed?

Does "ours" always refer to the branch that HEAD was pointing to when the merge began? If so then why not use a clear possessive reference like "current branch's" instead of using a possessive pronoun like "ours" that is referentially ambiguous (since both branches are technically ours)?

Or just use the branch name (instead of saying "ours" just say "local master's" or such)?

The most confusing part to me is if I specify in a specific branch's .gitattributes file. Lets say in test branch I have the following .gitattributes file:

config.xml merge=ours

Now I checkout and point HEAD to master then merge in test. Since master is ours, and test's .gitattributes is not checked out, will it even have an effect? If it does have an effect, since master is now "ours", then what will happen?

See also: Who is "us" and who is "them" according to Git? I have an answer there where I explain in detail what is us / ours and them / theirs and what they mean / how they change for git merge, git cherry-pick, git rebase, and git revert.
Hell yes. Whoever came up with this naming should be on the naughty stool; it's way too ambiguous.
OMG thank you for posting this. Whoever came up with that naming clearly was confused as well.

C
Community

I suspect you're confused here because it's fundamentally confusing. To make things worse, the whole ours/theirs stuff switches roles (becomes backwards) when you are doing a rebase.

Ultimately, during a git merge, the "ours" branch refers to the branch you're merging into:

git checkout merge-into-ours

and the "theirs" branch refers to the (single) branch you're merging:

git merge from-theirs

and here "ours" and "theirs" makes some sense, as even though "theirs" is probably yours anyway, "theirs" is not the one you were on when you ran git merge.

While using the actual branch name might be pretty cool, it falls apart in more complex cases. For instance, instead of the above, you might do:

git checkout ours
git merge 1234567

where you're merging by raw commit-ID. Worse, you can even do this:

git checkout 7777777    # detach HEAD
git merge 1234567       # do a test merge

in which case there are no branch names involved!

I think it's little help here, but in fact, in gitrevisions syntax, you can refer to an individual path in the index by number, during a conflicted merge

git show :1:README
git show :2:README
git show :3:README

Stage #1 is the common ancestor of the files, stage #2 is the target-branch version, and stage #3 is the version you are merging from.

The reason the "ours" and "theirs" notions get swapped around during rebase is that rebase works by doing a series of cherry-picks, into an anonymous branch (detached HEAD mode). The target branch is the anonymous branch, and the merge-from branch is your original (pre-rebase) branch: so "--ours" means the anonymous one rebase is building while "--theirs" means "our branch being rebased".

As for the gitattributes entry: it could have an effect: "ours" really means "use stage #2" internally. But as you note, it's not actually in place at the time, so it should not have an effect here ... well, not unless you copy it into the work tree before you start.

Also, by the way, this applies to all uses of ours and theirs, but some are on a whole file level (-s ours for a merge strategy; git checkout --ours during a merge conflict) and some are on a piece-by-piece basis (-X ours or -X theirs during a -s recursive merge). Which probably does not help with any of the confusion.

I've never come up with a better name for these, though. And: see VonC's answer to another question, where git mergetool introduces yet more names for these, calling them "local" and "remote"!


OMG. thanks torek. i was in the middle of a rebase and I couldn't understand why my changes on my branch is not between <<<<<<< HEAD and =======. Tnx a lot
@torek, this has to be one of the best explanations of this that I have come across. Thank you for putting so much thought and effort into this response, it's very helpful.
In the case where there is no branch names, is there a problem with using the commit-ID ?
@Joseph: No, a commit ID works fine. But the issue here is not the original commit hash, but rather the meaning of ours and theirs, which amounts to selecting the file (blob) hash within some commit. If you use a commit hash ID you must then also add the file path, e.g., a123456:path/to/file.ext.
@JānisElmeris: yes, git stash apply literally runs the internal git merge code (git merge-recursive or git merge-ort depending on Git version). The merge base is the original commit, HEAD is the current commit, and the "theirs" version is the stashed w commit. When using --index with git stash pop the i commit's changes are applied with git apply rather than git merge though.
N
Nitay

I know this has been answered, but this issue confused me so many times I've put up a small reference website to help me remember: https://nitaym.github.io/ourstheirs/

Here are the basics:

Merges:

$ git checkout master 
$ git merge feature

If you want to select the version in master:

$ git checkout --ours codefile.js

If you want to select the version in feature:

$ git checkout --theirs codefile.js

Rebases:

$ git checkout feature 
$ git rebase master 

If you want to select the version in master:

$ git checkout --ours codefile.js

If you want to select the version in feature:

$ git checkout --theirs codefile.js

(This is for complete files, of course)


That website is super-helpful. The flow-chart style and color-coded words make the website much easier to understand than the SO answers. Thank you.
Thank you, that's the simple explanation by example that I was looking for. The other answers talk so much about why you might be confused, and what the terms are supposed to mean, etc., that the answers become confusing themselves.
This answer is Gold. I keep on coming to this answer everytime I have to do ours/theirs during a rebase merge conflict.
k
kenorb

The 'ours' in Git is referring to the original working branch which has authoritative/canonical part of git history.

The 'theirs' refers to the version that holds the work in order to be rebased (changes to be replayed onto the current branch).

This may appear to be swapped to people who are not aware that doing rebasing (e.g. git rebase) is actually taking your work on hold (which is theirs) in order to replay onto the canonical/main history which is ours, because we're rebasing our changes as third-party work.

The documentation for git-checkout was further clarified in Git >=2.5.1 as per f303016 commit:

--ours --theirs When checking out paths from the index, check out stage #2 ('ours') or #3 ('theirs') for unmerged paths. Note that during git rebase and git pull --rebase, 'ours' and 'theirs' may appear swapped; --ours gives the version from the branch the changes are rebased onto, while --theirs gives the version from the branch that holds your work that is being rebased. This is because rebase is used in a workflow that treats the history at the remote as the shared canonical one, and treats the work done on the branch you are rebasing as the third-party work to be integrated, and you are temporarily assuming the role of the keeper of the canonical history during the rebase. As the keeper of the canonical history, you need to view the history from the remote as ours (i.e. "our shared canonical history"), while what you did on your side branch as theirs (i.e. "one contributor's work on top of it").

For git-merge it's explain in the following way:

ours This option forces conflicting hunks to be auto-resolved cleanly by favoring our version. Changes from the other tree that do not conflict with our side are reflected to the merge result. For a binary file, the entire contents are taken from our side. This should not be confused with the ours merge strategy, which does not even look at what the other tree contains at all. It discards everything the other tree did, declaring our history contains all that happened in it. theirs This is the opposite of ours.

Further more, here is explained how to use them:

The merge mechanism (git merge and git pull commands) allows the backend merge strategies to be chosen with -s option. Some strategies can also take their own options, which can be passed by giving -X

So sometimes it can be confusing, for example:

git pull origin master where -Xours is our local, -Xtheirs is theirs (remote) branch

git pull origin master -r where -Xours is theirs (remote), -Xtheirs is ours

So the 2nd example is opposite to the 1st one, because we're rebasing our branch on top of the remote one, so our starting point is remote one, and our changes are treated as external.

Similar for git merge strategies (-X ours and -X theirs).


this answer seems out of date => "git merge --ours" is not a valid option
@AlexanderMills The answer didn't talk about git merge, but git pull and git checkout as example. If you like to use this parameter with git merge, you should use -X ours. You can still use --ours syntax for git checkout. I've clarified the answer further more.
Your explanation on way rebase is backwards makes perfect sense, and I can probably remember it without Googling. Thanks you!
K
Kamafeather

I know it doesn't explain the meaning but I've made myself a little image, as reference to remind which one to use:

https://i.stack.imgur.com/NdQpP.png

Hope it helps!

PS - Give a check also to the link in Nitay's answer 🙂


I spent way too long reading some of these huge books of an answer, your image although not perfect, explained it close to perfectly for me in a much more succinct way. Version 2 could use a explanation of the term HEAD visually in this context
Tnx for the compliment! I'm glad it helped others as it visually helped me! I omitted HEAD because it's a time-related information, of a pointer at a specific moment in time. With the image I wanted to give a "timeless" view; although I imagine that it is not obvious to grasp for a git newcomer. To explain/show the HEAD I would need to show one for each git .. command (after checkouts, after merge, after rebase); IMHO it might result in a more confused image; so I took for granted that one already has the knowledge/concepts of history, HEAD, checkout, merge and rebase.
M
Mecki

Ours: This is the branch you are currently on.

Theirs: This is the other branch that is used in your action.

So if you are on branch release/2.5 and you merge branch feature/new-buttons into it, then the content as found in release/2.5 is what ours refers to and the content as found on feature/new-buttons is what theirs refers to. During a merge action this is pretty straight forward.

The only problem most people fall for is the rebase case. If you do a re-base instead of a normal merge, the roles are swapped. How's that? Well, that's caused solely by the way rebasing works. Think of rebase to work like that:

All commits you have done since your last pull are moved to a branch of their own, let's name it BranchX. You checkout the head of your current branch, discarding any local changes you had but that way retrieving all changes others have pushed for that branch. Now every commit on BranchX is cherry-picked in order old to new to your current branch. BranchX is deleted again and thus won't ever show up in any history.

Of course, that's not really what is going on but it's a nice mind model for me. And if you look at 2 and 3, you will understand why the roles are swapped now. As of 2, your current branch is now the branch from the server without any of your changes, so this is ours (the branch you are on). The changes you made are now on a different branch that is not your current one (BranchX) and thus these changes (despite being the changes you made) are theirs (the other branch used in your action).

That means if you merge and you want your changes to always win, you'd tell git to always choose "ours" but if you rebase and you want all your changes to always win, you tell git to always choose "theirs".


D
DenisKolodin

I'll post my memo here, because I have to come back here again and again.

SCENARIO 1. Normal developer: You are developer who can't merge to master and have to play with feature branches only.

Case 1: master is a king. You want to refresh your feature branch (= rebase to master), because master contains new updates of dependencies and you want to overwrite your modest changes.

git checkout master
git pull

git checkout feature
git rebase -X ours master

Case 2: you are a king. You want to rebase your feature branch to master changes. But you did more than your colleagues had and want to use your own changes in a priority.

git checkout master
git pull

git checkout feature
git rebase -X theirs master

IMPORTANT: As you can see normal developers should prefer rebase and repeat it every morning like exercises/coffee.

SCENARIO 2. Merging-sensei: You are a team-lead and want to merge other branches and push a merged result directly to a master. master is a branch you will change.

Case 1: master is a king You want to merge third-party branch, but master is a priority. feature is a branch that your senior did.

git checkout feature
git pull

git checkout master
git merge -X ours feature

Case 2: new changes is a king When your senior developer released a cool feature and you want to overwrite the old s**t in the master branch.

git checkout feature
git pull

git checkout master
git merge -X theirs feature

REMEMBER: To remember in a midnight which one to choose: master is ours ALWAYS. And theirs is a feature that theirs have done.


Note: -X means --strategy-option and allows to favour the code from theirs or ours
J
Joshua Ryan

From git checkout's usage:

-2, --ours            checkout our version for unmerged files
-3, --theirs          checkout their version for unmerged files
-m, --merge           perform a 3-way merge with the new branch

When resolving merge conflicts, you can do git checkout --theirs some_file, and git checkout --ours some_file to reset the file to the current version and the incoming versions respectively.

If you've done git checkout --ours some_file or git checkout --theirs some_file and would like to reset the file to the 3-way merge version of the file, you can do git checkout --merge some_file.


P
Peter Hollingsworth

Just to clarify -- as noted above when rebasing the sense is reversed, so if you see

<<<<<<< HEAD
        foo = 12;
=======
        foo = 22;
>>>>>>> [your commit message]

Resolve using 'mine' -> foo = 12

Resolve using 'theirs' -> foo = 22


S
Szczepan Hołyszewski

There is no precise meaning, precisely because these terms mean the opposite things depending on whether you are merging or rebasing. THE natural way of thinking about two branches is "my work" and "someone else's work". The choice of terminology that obscures this classification is absolutely THE worst design choice in git. It must have been inspired by accounting's "credit" and "debit" or "assets" and "liabilities" - same headache.


I beg to differ, there is a precise meaning: "ours" means "where HEAD is", in a merge or a rebase: stackoverflow.com/a/2960751/6309
"Where HEAD is" is a tool-centered rather than user-centered notion. That's precisely the problem.
I see your point of view now. You are correct, although, from that perspective (tool vs. user), there are a lot of questionable design decisions indeed. Some are improving: git checkout vs. git switch/git restore come to mind.