web-dev-qa-db-ja.com

"git merge -s ours"の "theirs"バージョンはありますか?

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

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

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

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

760
elmarco

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

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
895
Alan W. Smith

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を引数として使ってスクリプトにラップすることができます。

このソリューションは、git merge -s theirs branchBと同じように、マージコミットの1番目と2番目の親を保持します。

192
Paul Pladijs

古いバージョンのgitでは、 "theirs"マージ戦略を使うことができました。

git pull --strategy=theirs remote_branch

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

git fetch Origin
git reset --hard Origin

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

83
Pat Notz

私は今からPaul Pladijsからの答えを使いました。私は見つけました、あなたは「普通の」マージをすることができます、衝突が起こるので

git checkout --theirs <file>

他のブランチからのリビジョンを使用して競合を解決します。各ファイルに対してこれを実行すると、期待通りの動作になります。

git merge <branch> -s theirs

とにかく、努力はマージ戦略の場合よりも大きいのです。 (これはgitバージョン1.8.0でテストされています)

60
musicmatze

あなたが望む結果が何であるかは完全には明らかではないので、答えと彼らのコメントでそれをする「正しい」方法についていくらか混乱があります。概要を説明し、次の3つの選択肢を見てみます。

マージして競合のためにBを使用してください

これはnot "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

これは何ですか。 アランW.スミスの答え します。

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からのコミットであり、2番目のコミットだけが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の答え がすることです(/一時的なブランチを必要とせずに)。

53
siegi

私は自分の問題を使って解決した

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

あなたがブランチAにいるならば、してください:

git merge -s recursive -X theirs B

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

14
rafalmag

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

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

私はあなたがmasterから分岐を作成し、masterにマージしてmasterの中の古いものを上書きしたいと思います。私がこの記事に出くわしたとき、それはまさに私がやりたかったことです。

1つのブランチを他のブランチに最初にマージすることを除いて、それがあなたがやりたいこととまったく同じようにしてください。私はちょうどこれをしました、そしてそれはとてもうまくいきました。

git checkout Branch
git merge master -s ours

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

git checkout master
git merge Branch
8
Gandalf458

マージするブランチから only inputを受け取るマージを本当に適切に実行するには、次のようにします。

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

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

git commit --amend

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

これはサブモジュールではうまくいきません。

6
thoutbeckers

を参照してください。浜野順雄の広く引用されている答え :コミットしたコンテンツを破棄する場合は、コミットを破棄するか、いずれにせよメインヒストリーから除外してください。提供するものが何もないコミットからコミットメッセージを読んでいる将来、みんなに迷惑をかけるのはなぜでしょうか。

しかし、時には管理上の要件、またはおそらく他の何らかの理由があります。何も貢献していないコミットを本当に記録しなければならないような状況では、次のようにします。

(編集:うわー、私はこれまで間違っていたことをどうにかしていた。これはうまくいく。)

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

なぜ存在しないのですか?

gitコマンドで別のブランチを作成する方法 」でgit merge -s theirsをシミュレートする方法について説明しましたが、Git 2.15(2017年第4四半期)が明確になっています。

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

コミットc25d98b (25 Sep 2017) - Junio C Hamano(gitster を参照。
Junio C Hamano - gitster - in commit 4da3e23 、2017年9月28日にマージ)

マージ戦略: "-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' -

ヤロスラフHalchenkoはその戦略のためにもう一度主張しようとします、 しかし、Junio C. Hamanoは付け加えます

私たちのものと彼らのものが対称的ではないのは、あなたがあなたであり彼らではないからです。私たちの歴史と彼らの歴史の支配と所有は対称的ではありません。

彼らの歴史がメインラインであると決心したならば、あなたはむしろあなたの開発ラインをサイドブランチとして扱い、その方向にマージをしたいと思うでしょう、すなわち結果として生じるマージの最初の親は彼らの歴史と2番目のコミットです。親はあなたの歴史の最後の悪い人です。ですから、あなたは最初の親の賢明さを保つために "checkout their-history && merge -s ours your-history"を使うことになるでしょう。

そしてその時点で、 "-s ours"の使用はもはや "-s theirs"の欠如に対する回避策ではありません。
それは望ましい意味論の適切な部分です。すなわち、生き残った正規履歴行の観点からは、それが行ったことを保存し、他の履歴行がしたことを無効にしたいです

2
VonC

これはgit配管コマンド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>
2
Michael R

この答えは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
0
Brain2000

'git merge -s theirs branchB'と同じ(親の順序を保つ)

マージ前: enter image description here 

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

マージを行います。

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

我々のしたこと ?私たちは、2人の親が私たちと彼らのもの、そしてコミットの内容がbranchBである新しいコミットを作成しました

マージ後: enter image description here 

より正確に:

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

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

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

これは不器用に思えますが、うまくいくはずです。私がこの解決策について本当に嫌いだと思うのは、gitの履歴が混乱を招くことだけです。しかし、少なくとも履歴は完全に保存され、削除されたファイルに対して特別なことをする必要はありません。

0
briemers

これにより、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
0