「彼らの」バージョンの「git merge -s ours」はありますか?


876

を使用してトピックブランチ「B」を「A」にマージするとgit merge、いくつかの競合が発生します。「B」のバージョンを使用すると、すべての競合を解決できることを知っています。

私は承知していgit merge -s oursます。しかし、私が欲しいのはのようなものですgit merge -s theirs

なぜそれが存在しないのですか?既存のgitコマンドとマージして競合した後、どうすれば同じ結果を得ることができますか?(git checkoutBからのすべてのマージされていないファイル)

更新:ブランチA(ツリーのBバージョンへのマージコミットポイント)から何かを単に破棄する「解決策」は、私が探しているものではありません。


1
また、この回答を参照してください。stackoverflow.com/questions/928646/...を -それは代わりにAの使用バージョンBに例を変更するには些細だ
Robie Basak

8
SO答えを参照してください別のように一方の分岐を作るためのgitコマンドをするためにすべてのために現在可能な方法をシミュレートgit merge -s their
VonC 2011年

4
あなたが本当に探していないのでgit merge -s theirs(それがで容易に実現することができgit merge -s ours-s私たちは完全に...マージからブランチの変更を無視するので、一時的なブランチ)
ニコロマティーニを

21
@Torek-Git開発者は本当にそれを提供するの不快であることtheirsに加えてours??? これは、Gitの高度なエンジニアリングと設計の問題の1つである不整合の症状です。
JWW

3
@jwwここでの問題は、「git merge -s ours」が攻撃的であるということではなく、直観に反することです。OPの質問から、そのような機能が追加された場合、彼が実際にやりたいことが「git merge -s recursive -X theirs」であるときに、誤ってそれを使用することになることがわかります。別のブランチを上書きして別のブランチのバージョンとの競合をマージすることはよくありますが、現在のブランチを別のブランチで完全に上書きして、現在のブランチの変更を完全に破棄することは、本当に例外的なケースです。
ThomazMoura

回答:


1019

-Xオプションをに追加しますtheirs。例えば:

git checkout branchA
git merge -X theirs branchB

すべてが望ましい方法でマージされます。

私が見た唯一の問題は、ファイルがbranchBから削除された場合です。git以外のものが削除を行った場合、それらは競合として表示されます。

修正は簡単です。git rm削除されたファイルの名前を指定して実行します。

git rm {DELETED-FILE-NAME}

その後、は-X theirs期待どおりに動作するはずです。

もちろん、git rmコマンドを使用して実際に削除することで、最初から競合が発生するのを防ぐことができます。


:長い形式のオプションもあります。

それを使用するには、以下を置き換えます。

-X theirs

と:

--strategy-option=theirs

6
元の質問に対するより良い解決策(Paul Pladijs)については、以下の他の回答を参照してください。
マルコム

204
これは「マージ戦略theirs」と同じではないことに注意する価値があります。-Xtheirsは、再帰的戦略に適用される戦略オプションです。これは、再帰的な戦略は可能な限りすべてをマージし、競合が発生した場合にのみ「彼ら」のロジックにフォールバックすることを意味します。これは上記のようなほとんどの場合に必要なことですが、これは「ブランチBからすべてをそのまま取得する」と同じではありません。とにかく、実際のマージを行います。
ティムール

2
他のコマンドでも動作します。「git cherry-pick sha1 -X theirs」を実行しました。ありがとう!
Max Hohenegger、2014年

48
これは正しいように見えますが、実際には間違っているので、ひどい答えです。「git merge -X theirs」、「git merge -s theirs」が行うことを実行しません。現在のブランチがマージされたブランチのコンテンツで置き換えられることはありません。「彼ら」の変更を優先しますが、衝突の場合のみです。したがって、結果のコミットは「theirs」ブランチとはかなり異なる可能性があります。これは、質問の投稿者が考えていたものではありません。
Ivan Krivyakov 2017年

7
@ user3338098:はい、そうです。質問を読み直しましたが、あまりよくありません。残念ながら、混乱の根本的な原因は答えではなく、問題でもありません。マージ戦略とマージ戦略のオプション「再帰的」に同じ名前「ours」を付けるのはgit作成者の設計上の選択です。この場合の混乱は事実上避けられません。
Ivan Krivyakov 2017

218

BranchBをチェックアウト済みBranchAにマージするための可能なテスト済みソリューション:

# in case branchA is not our current branch
git checkout branchA

# make merge commit but without conflicts!!
# the contents of 'ours' will be discarded later
git merge -s ours branchB    

# make temporary branch to merged commit
git branch branchTEMP         

# get contents of working tree and index to the one of branchB
git reset --hard branchB

# reset to our merged commit but 
# keep contents of working tree and index
git reset --soft branchTEMP

# change the contents of the merged commit
# with the contents of branchB
git commit --amend

# get rid off our temporary branch
git branch -D branchTEMP

# verify that the merge commit contains only contents of branchB
git diff HEAD branchB

自動化するには、branchAとbranchBを引数として使用してスクリプトにラップします。

このソリューションでは、期待どおりに、マージコミットの最初と2番目の親が保持されますgit merge -s theirs branchB


Q:なぜbranchTEMPが必要なのですか?あなただけではないのですgit reset --soft branchAか?
cdunn2001

4
@ cdunn2001:どういうわけか私は同じことを考えましたが、違います。git reset --hardコミットがbranchA指す変更に注意してください。
伊藤剛

5
愚かな質問をして申し訳ありませんが、なぜこの方法が-xtheirsの方が優れているのですか?長所と短所は何
ですか

9
@ chrispepper1989 -x theirs競合のみに影響し、私たちの塊がクリーンに適用できる場合は、結果として生じるマージに到達します。この場合、最後のコマンドで示されているように、競合があったかどうかに関係なく、branchB と完全に同一のマージを取得しています。
UncleZeiv

2
@UncleZeivは説明に感謝します。したがって、基本的に「それら」を実行すると、競合しない変更とファイルが保持され、プルされたコードとは異なるintコードが生成されます。
chrispepper1989

89

古いバージョンのgitでは、「それら」のマージ戦略を使用できました。

git pull --strategy=theirs remote_branch

しかし、このメッセージで説明されているように、このメッセージは浜野純生(Gitメンテナー)によって削除されました。リンクに記載されているように、代わりに次のようにします。

git fetch origin
git reset --hard origin

ただし、これは実際のマージとは異なることに注意してください。あなたのソリューションはおそらくあなたが本当に探しているオプションです。


7
浜野淳夫さんの説明が全くわかりません。git reset --hard origin彼らのスタイルのマージのソリューションはどうですか?BranchAをBranchAにマージしたい場合(Alan W. Smithの回答のように)、resetメソッドを使用してどのように実行しますか?
James McMahon

3
@ジェームズ・マクマホン:ジュニオ・C・ハマノのポイントはgit reset --hard「彼ら」スタイルの合併ではない。もちろん、git reset --hardマージコミットや、その問題に対するコミットは作成されません。彼のポイントは、HEAD内のものを他のもので置き換えるためにマージ使用すべきではないということです。しかし、私は必ずしも同意しません。
伊藤剛

11
theirs根拠が不完全だったために削除されたのは残念です。それはコードが良いそれらの例を許すことに失敗しました、それはただ上流が異なる哲学に基づいて維持されているということです、その意味で「悪い」ので、人は上流で最新に保つことを望みますが、同時に、適切なコード「修正」を保持します[git&msysgitには、ターゲットプラットフォームの考え方が異なるため、この「矛盾」がいくつかあります]
Philip Oakley

1
また、私が今行き詰まっているユースケースも見当たりません。ブランチを他の誰かと共有していて、私たちは2人で(異なるファイルの)変更を同時にプッシュしました。そこで、ローカルにあるすべての古いバージョンを上書きし、代わりに彼の新しいバージョンを使用したいと考えています。彼は私が更新したファイルに対しても同じことをしたいと思っています。「リセット」するものは何もありません。また、個々のファイルをチェックアウトするソリューションは、ファイルが20個以下の場合は実用的ではありません。
szeitlin 2015

2
私は哲学を本当に理解していません。theirs2つの別々のブランチでいくつかのファイルを誤って変更し、すべてのファイルに対して手動で行う必要なく1つの変更を破棄したかったので、私は使用しました。
sudo

65

望ましい結果が完全に明確ではないため、回答とコメントで「正しい」方法を実行することについて混乱が生じます。概要を説明し、次の3つのオプションを確認します。

マージしてみて、競合にBを使用してください

これはない「ための彼らのバージョンgit merge -s ours」ではなく「のための彼らのバージョンgit merge -X ours(のために短いです」git merge -s recursive -X ours):

git checkout branchA
# also uses -s recursive implicitly
git merge -X theirs branchB

これは、たとえばAlan W. Smithの回答が行うことです。

Bのコンテンツのみを使用

これにより、両方のブランチのマージコミットが作成されますが、からのすべての変更が破棄されbranchA、からの内容のみが保持されbranchBます。

# Get the content you want to keep.
# If you want to keep branchB at the current commit, you can add --detached,
# else it will be advanced to the merge commit in the next step.
git checkout branchB

# Do the merge an keep current (our) content from branchB we just checked out.
git merge -s ours branchA

# Set branchA to current commit and check it out.
git checkout -B branchA

マージコミット最初の親が今からということであることに注意してくださいbranchBとだけ秒からですbranchA。これは例えばGandalf458の答えがすることです。

Bのコンテンツのみを使用し、正しい親の順序を維持する

これが本当の「彼らのバージョンgit merge -s ours」です。以前のオプションと同じ内容(つまり、からのみbranchB)ですが、親の順序は正しいです。つまり、最初の親はからbranchA、2番目はからbranchBです。

git checkout branchA

# Do a merge commit. The content of this commit does not matter,
# so use a strategy that never fails.
# Note: This advances branchA.
git merge -s ours branchB

# Change working tree and index to desired content.
# --detach ensures branchB will not move when doing the reset in the next step.
git checkout --detach branchB

# Move HEAD to branchA without changing contents of working tree and index.
git reset --soft branchA

# 'attach' HEAD to branchA.
# This ensures branchA will move when doing 'commit --amend'.
git checkout branchA

# Change content of merge commit to current index (i.e. content of branchB).
git commit --amend -C HEAD

これはPaul Pladijsの答えです(一時的なブランチを必要としない)。


オプション3のよりクリーンなバージョンgit checkout branchA; git merge -s ours --no-commit branchB; git read-tree -um @ branchB; git commit
2016年

@jthill:バージョンはより簡潔read-treeですが、平均的なgitユーザーが慣れていない可能性がある低レベル(配管)コマンドも使用します(少なくとも私は;-)ではありません)。回答のソリューションは、ほとんどのgitユーザーが知っておくべき高レベル(「磁器」)コマンドのみを使用しています。私はそれらを好むがそれにもかかわらずあなたのバージョンをありがとう!
siegi 2016年

最後から2番目のステップ(ブランチAのチェックアウト)を説明できますか?あるべきではないようです。
Patrick

@Patrick、このステップは必須です。これをスキップすると、同じコミットが取得されますが、このコミットを指すブランチはありません。したがって、別のコミット/ブランチに切り替えると、最後のコマンド(…commit --amend…)で行ったコミットは「失われます」。時間があるとすぐに、この回答にいくつかのグラフィカルな説明を追加する予定です... ;-)
siegi

62

私は今からポール・プラディスの答えを使いました。私が知った、あなたは「通常の」マージを行うことができ、競合が発生するので、

git checkout --theirs <file>

他のブランチのリビジョンを使用して競合を解決します。これをファイルごとに行うと、期待どおりの動作になります

git merge <branch> -s theirs

とにかく、マージ戦略よりも労力がかかります!(これはgitバージョン1.8.0でテストされました)


1
ファイルのリストを取得できると便利です。たとえば、git ls-files --modified | xargs git add私はこれを両サイドのマージに追加したいと思っていました:/
andho

実際にはgitは両側に追加されたファイルを返すgit ls-files --modifiedので、これも実行可能な解決策だと思います。
andho

1
これも追加してくれてありがとう。多くの場合、ファイルごとのベースでは必要ありません。また、gitステータスの一番下に「Unmerged Paths」と表示されます。未解決のパスのリストを取得するには、私はこのエイリアスを使用:git config --global alias.unresolved '!git status --short|egrep "^([DAU])\1"'
メルヴィン

との意味は-X何ですか?-Xとは-sどう違いますか?ドキュメントが見つかりません。
レイヤン

21

私は使用して問題を解決しました

git checkout -m old
git checkout -b new B
git merge -s ours old

「古い」ブランチからのブランチ「B」
elmarco

13

git mergeを使用してトピックブランチ「B」を「A」にマージすると、いくつかの競合が発生します。>すべての競合は「B」のバージョンを使用して解決できることを知っています。

私はgit merge -s oursを知っています。しかし、私が欲しいのはgit merge> -s theirのようなものです。

私はあなたがマスターからブランチを作成し、今マスターにマージしてマスターの古いものを上書きしたいと仮定しています。これは、この投稿に出くわしたときにまさにやりたかったことです。

最初に1つのブランチを他のブランチにマージすることを除いて、それがしたいことを正確に実行してください。私はこれをやっただけで、うまくいきました。

git checkout Branch
git merge master -s ours

次に、マスターをチェックアウトし、ブランチをマージします(これでスムーズに進みます)。

git checkout master
git merge Branch

1
ありがとう。これは、最も単純で最も正しい、受け入れられる答えであるはずです。ブランチがマスターの背後にある/競合している場合は、すべてをマスターにマージする前にマージしてすべてを機能させるブランチジョブです。
StackHola

これは素晴らしく機能しました、ありがとう。
コディグランサム

12

ブランチAにいる場合:

git merge -s recursive -X theirs B

gitバージョン1.7.8でテスト済み


8

マージするブランチからの入力のみを取るマージを本当に適切に行うには、

git merge --strategy=ours ref-to-be-merged

git diff --binary ref-to-be-merged | git apply --reverse --index

git commit --amend

私が知っているどのシナリオでも競合はありません。追加のブランチを作成する必要はなく、通常のマージコミットのように動作します。

ただし、これはサブモジュールではうまく機能しません。


ここで-Rは何をしますか?
P.マイヤーノア2015年

これにより、「移動および変更」されたファイルの履歴が失われます。私は正しいですか?
elysch

1
-Rは--reverseです。答えを自己文書化するように更新しました。
Elijah Lynn

マージしようとしているファイルが着信ブランチで削除されている場合、これは機能しないようです。
solveJ

7

なぜそれが存在しないのですか?

あるブランチを別のブランチにするためのgitコマンド」でシミュレートする方法について言及しましたがgit merge -s theirs、Git 2.15(2017年第4四半期)がより明確になっていることに注意してください。

-X<option>マージ用の ' ' のドキュメントは、「-s theirs」が存在することを示唆するように誤解を招くように書かれていましたが、そうではありません。

Junio C Hamano()によるcommit c25d98b(2017年9月25日)を参照してください。(による合併Junio C浜野- -4da3e23コミット、2017年9月28日に)gitster
gitster

マージ戦略:「-s theirs」が存在することを示唆することを避けます

説明-Xoursマージオプションは、それは非常に異なっていることを読者に伝え括弧付きのノート持って-s ours正しい、しかし、の説明-Xtheirsそれはそれは不用意に「これは反対であると言い、次のours読者にも必要という誤った印象を与え、」とは非常に異なり-s theirs、実際には存在しないことを警告されます。

-Xtheirsある戦略オプション再帰的戦略に適用されます。これは、再帰的な戦略でも可能な限りマージしtheirs、競合が発生した場合にのみ " "ロジックにフォールバックすることを意味します。

theirsマージ戦略の妥当性に関するこの議論は、2017年9月のこのスレッドで最近取り上げられました古い(2008)スレッドを
認識します

簡単に言うと、前の議論は「-s theirs間違ったワークフローを助長するので、「」は欲しくない」と要約できます。

それはエイリアスについて言及しています:

mtheirs = !sh -c 'git merge -s ours --no-commit $1 && git read-tree -m -u $1' -

ヤロスラフ・ハルチェンコはその戦略をもう一度提唱しようとしますが、ジュニオ・C・ハマノは次のように付け加えます

私たちと彼らの関係が対称的ではない理由は、あなたがあなたであり彼らではないからです。私たちの歴史とその歴史の管理と所有権は対称的ではありません。

それらの履歴がメインラインであると判断したら、開発ラインをサイドブランチとして扱い、その方向にマージする必要があります。つまり、結果のマージの最初の親は、それらの履歴に対するコミットであり、2番目は親はあなたの歴史の最後の悪い人です。そのcheckout their-history && merge -s ours your-historyため、「」を使用して、最初の親子関係を賢明に保つことになります。

その時点で、「-s ours」の使用は「」の欠如に対する回避策ではなくなりました-s theirs
これは、目的のセマンティクスの適切な部分です。つまり、生き残った正規履歴行の観点から、それが行ったことを保持し、他の履歴行が行ったことを無効にしたいとします。

マイク・ビートンがコメントしたように、ジュニオは付け加えた。

git merge -s ours <their-ref>効果的に「<their-ref>永続的に無視されるコミットとして、ブランチで行われたコミットにマークを付ける」;
そして、これが重要になるのは、後でブランチのより後の状態からマージすると、無視された変更が反映されることなく、その後の変更が反映されるからです。


1
これは便利な回答ですが、Junio Cから理解したばかりの重要なポイントについては触れていません。浜野の回答:git merge -s ours <their-ref>コミットは永続的に無視されるコミットであるため、ブランチ上の<their-ref>までのコミットにマークを付けます'; あなたはその後、彼らのブランチの後の状態からマージする場合は、その後の変更は無視され、変更なしにもたらされるだろう、この問題、ため、これまでに提起されている。
MikeBeaton

1
@MikeBeatonありがとうございます。見やすくするために、回答にコメントを含めました。
VonC

5

浜野純夫の広く引用されている答えを参照してください。コミットされたコンテンツを破棄する場合は、コミットを破棄するか、いずれにしても、メインの履歴から除外してください。将来的に、提供するものがないコミットからのコミットメッセージを誰もが気にしないのはなぜですか?

ただし、管理上の要件やその他の理由がある場合もあります。何も貢献しないコミットを実際に記録する必要がある状況では、次のようにします。

(編集:わあ、なんとか前にこれを間違えたことがあります。これは機能します。)

git update-ref HEAD $(
        git commit-tree -m 'completely superseding with branchB content' \
                        -p HEAD -p branchB    branchB:
)
git reset --hard

3

これはgit plumbingコマンドのread-treeを使用していますが、全体的なワークフローが短くなっています。

git checkout <base-branch>

git merge --no-commit -s ours <their-branch>
git read-tree -u --reset <their-branch>
git commit

# Check your work!
git diff <their-branch>

0

これにより、newBranchが既存のbaseBranchにマージされます

git checkout <baseBranch> // this will checkout baseBranch
git merge -s ours <newBranch> // this will simple merge newBranch in baseBranch
git rm -rf . // this will remove all non references files from baseBranch (deleted in newBranch)
git checkout newBranch -- . //this will replace all conflicted files in baseBranch

git commit --amend例の最後に追加することをお勧めします。そうしないと、ユーザーがマージコミットを表示git logして、操作が完了したと想定する場合があります。
マイケルR

0

私はあなたが実際に欲しいものは次のとおりだと思います:

git checkout -B mergeBranch branchB
git merge -s ours branchA
git checkout branchA
git merge mergeBranch
git branch -D mergeBranch

これは不器用に思えますが、うまくいくはずです。このソリューションについて私が本当に嫌いな唯一の考えは、gitの履歴が混乱することです...しかし、少なくとも履歴は完全に保持され、削除されたファイルに対して特別な何かをする必要はありません。


0

'git merge -s theirs branchB'と同等(親の順序を維持)

マージ前:ここに画像の説明を入力してください

!!! あなたがきれいな状態にあることを確認してください!!!

マージを実行します。

git commit-tree -m "take theirs" -p HEAD -p branchB 'branchB^{tree}'
git reset --hard 36daf519952 # is the output of the prev command

我々のしたこと ?私たちは2人の親が私たちと彼らのものであり、コミットの内容がブランチBである新しいコミットを作成しました-彼らのもの

マージ後:ここに画像の説明を入力してください

より正確に:

git commit-tree -m "take theirs" -p HEAD -p 'SOURCE^{commit}' 'SOURCE^{tree}'

0

この答えはPaul Pladijsによって与えられました。私は彼のコマンドを受け取り、便宜上gitエイリアスを作成しました。

.gitconfigを編集して、以下を追加します。

[alias]
    mergetheirs = "!git merge -s ours \"$1\" && git branch temp_THEIRS && git reset --hard \"$1\" && git reset --soft temp_THEIRS && git commit --amend && git branch -D temp_THEIRS"

次に、次のコマンドを実行して、「git merge -s theirs A」を実行できます。

git checkout B (optional, just making sure we're on branch B)
git mergetheirs A

-1

最近、共通の履歴を共有する2つの別々のリポジトリに対してこれを行う必要がありました。私は始めました:

  • Org/repository1 master
  • Org/repository2 master

からのすべての変更repository2 masterをに適用してrepository1 master、repository2が行うすべての変更を受け入れたいと思っていました。gitの用語では、これ-s theirs BUTと呼ばれる戦略ですが、存在しません。ので、注意してください-X theirsあなたが何をしたいだろうそれのように命名されたが、それはありませ同じ(それもmanページでそう言います)。

私がこれを解決した方法はrepository2、新しいブランチに行って作ることでしたrepo1-merge。そのブランチで実行git pull git@gitlab.com:Org/repository1 -s oursしましたが、問題なくマージされました。次に、それをリモートにプッシュします。

次に戻ってrepository1新しいブランチを作成しrepo2-mergeます。そのブランチで実行git pull git@gitlab.com:Org/repository2 repo1-mergeすると、問題が発生します。

最後に、repository1新しいマスターにするためにマージ要求を発行するか、単にブランチとして保持する必要があります。


-2

シンプルで直感的な(私の意見では)2ステップの方法は

git checkout branchB .
git commit -m "Picked up the content from branchB"

に続く

git merge -s ours branchB

(2つのブランチをマージ済みとしてマークします)

唯一の欠点は、branchBで削除されたファイルが現在のブランチから削除されないことです。その後、2つのブランチ間の単純な差分は、そのようなファイルがあるかどうかを示します。

このアプローチは、何が行われたのか、何が意図されていたのかを後で改訂ログから明らかにします。


これは元の質問には正しいかもしれませんが、OPはこの回答が正しくないように2008年に質問を更新しました。
user3338098

1
@ user3338098うん、彼らは誤解を招くタイトルを左だけではそうは見えないアップデートをたたいたような残念な終わり、この答えがあるため....質問本体のない正確タイトルの質問の答えを。
RomainValeri

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