gitの「ours」と「theirs」の正確な意味は何ですか?


323

これは基本的な質問のように聞こえるかもしれませんが、私は回答を探しましたが、以前よりも混乱しています。

私のブランチを他のブランチにマージするとき、gitで「ours」と「theirs」はどういう意味ですか?どちらの枝も「私たち」です。

マージの競合では、「ours」は常に2つのバージョンの上部に表示されますか?

「私たち」は常に、マージの開始時にHEADが指していたブランチを指しますか?もしそうなら、なぜ参照が曖昧な「ours」のような所有格代名詞を使用するのではなく、「current Branch's」のような明確な所有参照を使用しないのはなぜですか(両方のブランチは技術的には私たちのものなので)。

または単にブランチ名を使用します(「ours」と言う代わりに「local master's」などと言うだけです)?

私にとって最も混乱する部分は、特定のブランチの.gitattributesファイルで指定した場合です。言うことができますテストブランチ、私は、次の.gitattributesファイルを持っています:

config.xml merge=ours

次に、チェックアウトしてHEADをマスターに向け、テストでマージします。以来マスターが私たち、そしてあるテストの.gitattributesチェックアウトされていない、それも効果があるのだろうか?効果がある場合、マスターは「私たち」になったので、どうなるでしょうか。

回答:


375

基本的に混乱しているので、ここで混乱しているのではないかと思います。さらに悪いことに、リベースを実行すると、私たち/彼らのスタッフ全員が役割を切り替えます(逆方向になります)。

最終的に、中にgit merge、「私たち」の分岐は、あなたがマージしている枝を指し

git checkout merge-into-ours

「theirs」ブランチは、マージする(単一の)ブランチを指します。

git merge from-theirs

ここでは、「ours」と「theirs」はある程度理にかなっています。とにかく「theirs」はおそらくあなたのものですが、「theirs」はあなたが走っていときのものではありませんgit merge

実際のブランチ名を使用するのはかなりクールかもしれませんが、より複雑なケースではバラバラです。たとえば、上記の代わりに、次のようにすることができます。

git checkout ours
git merge 1234567

生のcommit-IDでマージする場所。さらに悪いことに、これを行うこともできます。

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

その場合、関係するブランチ名はありません

ここでは少し助けになると思いますが、実際には、gitrevisions構文では、競合するマージ中にインデックス内の個々のパスを番号で参照できます

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

ステージ#1はファイルの共通の祖先、ステージ#2はターゲットブランチのバージョン、ステージ#3はマージ元のバージョンです。


「ours」と「theirs」の概念が入れ替わる理由はrebase、一連のチェリーピックをリベースして匿名ブランチ(デタッチされたHEADモード)にリベースするためです。ターゲットブランチは匿名ブランチであり、マージ元ブランチは元の(リベース前の)ブランチです。したがって、「-ours」は匿名の1つのリベースが構築されていることを意味し、「-theirs」は「リベースされるブランチ」を意味します。


gitattributesエントリについては、影響がある可能性があります。「ours」は実際には内部で「ステージ2を使用」を意味します。しかし、お気づきのように、その時点では実際には配置されていないので、ここでは効果がないはずです。

また、途中で、これは我々と彼らのすべての使用に適用されるが、一部はファイル全体のレベルである(-s oursマージ戦略のため、git checkout --oursマージ競合の間)と、いくつかは少しずつ基準である(-X oursまたは-X theirs中に-s recursiveマージ)。これはおそらく混乱の助けにはなりません。

ただし、これより良い名前を付けたことはありません。そして:別の質問に対するVonCの回答を参照してください。そこでgit mergetoolは、「ローカル」および「リモート」と呼ばれる、これらの名前のさらに多くの名前が紹介されています!


28
+1。リベース中にリバースされる私たちとそれらについては、次も参照してください:stackoverflow.com/a/2960751/6309stackoverflow.com/a/3052118/6309
VonC

1
2つのものが互いに「マージ」します。マージが発生すると、両側が互いに「マージ」されます。どちらか一方が「何にも統合されていない」というのは間違いだと思います。(指摘するように)関係するブランチ名がない場合は、コミット名が関係します(「ours」と「theirs」の代わりに「7777777's」と「1234567's」と言うことができます)。私はリベース中に何が起こるか理解しており、それがまったく混乱しているとは思いません。「HEAD」と「incoming's」は「ours」と「theirs」よりもうまく機能すると思います。なぜなら、「HEAD」が常に存在するためです(切り離されているかどうかは関係ありません)。
CommaToast 14

15
頭は心の座であり、アイデンティティの源であり、自己の源であるので、HEADが「私」(「私たち」)であると指し示しているものを考えることは、もう少し理にかなっています。私とHEADは2つ作ると思います)。それ以上なら、それは良いニーモニックデバイスになるでしょう。
CommaToast 14

1
そうは言っても、
リベースの

3
「その場合、関係するブランチ名はありません!」...代わりに、commit comment / hashを使用する必要があります。それが手に入れることができるものは何でも。実際には、「私たち」と「彼ら」よりも優れているものがあります。この混乱は何千時間も解消されたのではないでしょうか。C ++の「最も厄介な解析」に対するgitの答え;)
Jarrod Smith、

49

Git の「私たちのもの」は、gitの歴史の正式な/正規の部分を持つ元の作業ブランチを指します。

' theirs 'は、リベースするために作業を保持しているバージョンを指します(現在のブランチに再生される変更)。

これはやって(例えばリベースことに気づいていない人にスワップするように見えることがgit rebase)実際に(ある保留あなたの仕事取っている彼らをある標準的な/主な歴史上に再生するためには)我々我々がリベースしているので、私たちのサードパーティの仕事としての変更。

のドキュメントは、コミットgit-checkoutごとにGit> = 2.5.1でさらに明確化されました。f303016

--ours --theirs

インデックスからパスをチェックアウトするとき、マージされていないパスのステージ#2( 'ours')または#3( 'theirs')をチェックアウトします。

中にいることを注意git rebaseしてgit pull --rebase、「我々 」と「彼ら」は交換され表示される場合があります。--ours変更がリベースされる--theirsブランチからのバージョンを提供し、リベースされる作業を保持するブランチからのバージョンを提供します。

これはrebase、リモートでの履歴を共有の標準的なものとして扱い、リベースしているブランチで行われた作業を統合されるサードパーティの作業として扱い、一時的に次の役割を引き受けるワークフローで使用されるためです。リベース中の正規履歴の管理者。正規履歴の管理者として、リモートから履歴をours(つまり、「共有された正規履歴」)として表示し、サイドブランチで何をしたかtheirs(つまり、「1人の寄稿者の作業」)を表示する必要があります。

以下のためgit-mergeには、次のように説明します:

私たちのもの

このオプションは、バージョンを優先することで、競合するハンクを強制的に完全に自動解決します。私たちの側と競合しない他のツリーからの変更は、マージ結果に反映されます。バイナリファイルの場合、コンテンツ全体が私たちの側から取得されます。

これは、他のツリーに何が含まれているかをまったく考慮しない、私たちのマージ戦略と混同しないでください。それは他のツリーが行ったすべてを破棄し、私たちの歴史はその中で起こったすべてを含んでいると宣言します。

彼らのもの

これは私たちの反対です。

さらに、それらを使用する方法について説明します。

マージメカニズム(git mergeおよびgit pullコマンド)により、-sオプションでバックエンドマージ戦略を選択できます。いくつかの戦略も与えることで渡すことができ、独自のオプション、取ることができます-X<option>に引数をgit merge、および/またはをgit pull


したがって、時々混乱することがあります、例えば:

  • git pull origin master-Xours私たちのローカルはどこ-Xtheirsですか、彼らの(リモート)ブランチはどこ ですか
  • git pull origin master -r-Xours彼らの(リモート)はどこ-Xtheirsですか?

したがって、2番目の例は1番目のものとは逆です。なぜなら、ブランチをリモートのものの上にリベースしているので、開始点はリモート1であり、変更は外部として扱われます。

git merge戦略(-X oursおよび-X theirs)についても同様です。


2
この回答は古くなっているようです=> "git merge --ours"は有効なオプションではありません
Alexander Mills

@AlexanderMills答えはについては話されませんでしたgit mergegit pullgit checkout例として。このパラメータをgit mergeで使用する場合は、を使用する必要があります-X ours。の--ours構文は引き続き使用できますgit checkout。答えをさらに明確にしました。
kenorb

46

私はこれが答えられたことを知っていますが、この問題は私を混乱させるので、覚えるために小さなリファレンスWebサイトを何度も表示しました:https : //nitaym.github.io/ourstheirs/

基本は次のとおりです。

マージ:

$ git checkout master 
$ git merge feature

でバージョンを選択する場合master

$ git checkout --ours codefile.js

でバージョンを選択する場合feature

$ git checkout --theirs codefile.js

リベース:

$ git checkout feature 
$ git rebase master 

でバージョンを選択する場合master

$ git checkout --ours codefile.js

でバージョンを選択する場合feature

$ git checkout --theirs codefile.js

(もちろん、これは完全なファイル用です)


1
そのウェブサイトはとても役に立ちます。フローチャートスタイルと色分けされた単語により、SOの回答よりもWebサイトの理解がはるかに容易になります。ありがとうございました。
ロン

10
  • 私たちのもの:これはあなたが現在いるブランチです。
  • 彼らの:これはあなたの行動で使用される他のブランチです。

したがって、ブランチリリース/2.5を使用していて、ブランチ機能/新しいボタンをそこにマージする場合、リリース/2.5にあるコンテンツは私たちが参照しているものであり、フィーチャー/新しいボタンにあるコンテンツは彼らが参照しているものですに。マージアクションの間、これは非常に簡単です。

ほとんどの人が陥る唯一の問題はリベースのケースです。通常のマージではなくリベースを実行すると、役割が入れ替わります。どのようだ?まあ、それはリベースが機能する方法によってのみ引き起こされます。そのように動作するようにリベースを考えてください:

  1. 最後のプル以降に実行したすべてのコミットは、独自のブランチに移動されます。これをBranchXという名前にします
  2. 現在のブランチのヘッドをチェックアウトし、ローカルで行った変更を破棄しますが、他の人がそのブランチにプッシュしたすべての変更を取得します。
  3. 現在、BranchXでのすべてのコミットは、現在のブランチの古いものから新しいものへと順に選ばれています。
  4. BranchXは再び削除されるため、どの履歴にも表示されません。

もちろん、それは実際に起こっていることではありませんが、私にとっては良いマインドモデルです。また、2と3を見ると、なぜロールが交換されているのかがわかります。2の時点で、現在のブランチは何も変更されていないサーバーからのブランチになりました。つまり、これが私たちのブランチです(現在のブランチです)。行った変更は、現在の1(ではない別のブランチになりましたBranchX)ので、(あなたが行った変更にもかかわらず)これらの変更は、彼ら(あなたのアクションで使用される他の分岐)。

つまり、マージして変更を常に優先したい場合は、gitに常に「ours」を選択するように指示しますが、リベースしてすべての変更を常に優先したい場合は、gitに常に「theirs」を選択するよう指示します。


3

私はそれが意味を説明していないことを知っていますが、どちらを使用するかを思い出させるための参考として、私は小さなイメージを作りました:

ここに画像の説明を入力してください

それが役に立てば幸い!

PS- ニタイの答えのリンクもチェックしてください🙂


3

ここに何度も来なければならないので、ここにメモを投稿します。

シナリオ1.通常の開発者:あなたはブランチにマージできずmasterfeatureブランチだけで遊ぶ必要がある開発者です。

ケース1:マスターは王様です。依存関係の新しい更新が含まれていて、ささやかな変更を上書きしたいので、featureブランチを更新(= rebase to master)しmasterたい。

git checkout master
git pull

git checkout feature
git rebase -X ours master

ケース2:あなたは王様です。featureブランチをmaster変更にリベースしたい。しかし、あなたは同僚が持っていた以上のことを行い、自分の変更を優先的に使用したいと考えました。

git checkout master
git pull

git checkout feature
git rebase -X theirs master

重要:ご覧のとおり、通常の開発者はrebaseエクササイズ/コーヒーのように毎朝それを好み、繰り返す必要があります。

シナリオ2.マージ先生:あなたはチームリーダーであり、他のブランチをマージして、マージされた結果をマスターに直接プッシュしたいと考えています。master変更するブランチです。

ケース1:マスターは王様サードパーティのブランチをマージしたいが、masterが優先事項です。featureあなたの先輩がしたブランチです。

git checkout feature
git pull

git checkout master
git merge -X ours master

ケース2:新しい変更は王様ですシニアデベロッパーがクールなものfeatureをリリースし、古いs ** tをmasterブランチの。

git checkout feature
git pull

git checkout master
git merge -X theirs master

REMEMBER:いずれかを選択するためには、真夜中に覚えておくことがmasterあるours常に。そして、theirsあるfeature彼らが行っていること。


2

git checkoutの使用法から:

-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

マージの競合を解決するときはgit checkout --theirs some_filegit checkout --ours some_fileそれぞれ現在のバージョンと、着信のバージョンにファイルをリセットします。

完了したgit checkout --ours some_filegit checkout --theirs some_file、ファイルを3者間マージバージョンにリセットしたい場合は、を実行できますgit checkout --merge some_file

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.