1012

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

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

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

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

4

18 に答える 18

1172

同様の代替手段は--strategy-option(短い形式の-X) オプションで、これは を受け入れますtheirs。例えば:

git checkout branchA
git merge -X theirs branchB

-X oursただし、これはよりも同等です-s ours。主な違い-Xは、通常の再帰マージを実行し、選択した側を使用して競合を解決するのに対し-s ours、マージを変更して反対側を完全に無視することです。

場合によって-X theirsは、仮説の代わりに使用する主な問題-s theirsはファイルの削除です。この場合、git rm削除されたファイルの名前で実行してください:

git rm {DELETED-FILE-NAME}

その後、-X theirs期待どおりに動作する可能性があります。

もちろん、git rmコマンドで実際の削除を行うと、そもそも競合が発生するのを防ぐことができます。

于 2010-07-29T15:58:58.037 に答える
237

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

于 2011-02-11T13:42:30.537 に答える
100

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

git pull --strategy=theirs remote_branch

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

git fetch origin
git reset --hard origin

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

于 2008-10-06T13:28:10.957 に答える
87

あなたの望む結果が何であるかは完全には明らかではないため、回答とそのコメントでそれを行う「正しい」方法について混乱があります。概要を説明し、次の 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

マージ コミットの最初の親は frombranchBであり、2 番目の親のみがfrom であることに注意してくださいbranchA。これは、たとえばGandalf458 の回答が行うことです。

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

これが本当の「彼らのバージョンgit merge -s ours」です。前のオプションと同じ内容 (つまり、 from のみ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 の回答が行うことです(一時的なブランチは必要ありません)。

特殊なケース

のコミットbranchBが の祖先である場合branchAgit mergeは機能しません (「Already up to date.」のようなメッセージで終了するだけです)。

これまたは他の同様の/高度なケースでは、低レベルのコマンドgit commit-treeを使用できます。

于 2014-12-07T00:04:21.393 に答える
66

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

git checkout --theirs <file>

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

git merge <branch> -s theirs

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

于 2012-11-03T12:51:12.777 に答える
21

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

git checkout -m old
git checkout -b new B
git merge -s ours old
于 2008-10-06T11:34:59.203 に答える
11

ブランチ A にいる場合は、次のようにします。

git merge -s recursive -X theirs B

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

于 2012-04-12T19:17:23.857 に答える
9

Why doesn't it exist?

While I mention in "git command for making one branch like another" how to simulate git merge -s theirs, note that Git 2.15 (Q4 2017) is now clearer:

The documentation for '-X<option>' for merges was misleadingly written to suggest that "-s theirs" exists, which is not the case.

See commit c25d98b (25 Sep 2017) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 4da3e23, 28 Sep 2017)

merge-strategies: avoid implying that "-s theirs" exists

The description of -Xours merge option has a parenthetical note that tells the readers that it is very different from -s ours, which is correct, but the description of -Xtheirs that follows it carelessly says "this is the opposite of ours", giving a false impression that the readers also need to be warned that it is very different from -s theirs, which in reality does not even exist.

-Xtheirs is a strategy option applied to recursive strategy. This means that recursive strategy will still merge anything it can, and will only fall back to "theirs" logic in case of conflicts.

That debate for the pertinence or not of a theirs merge strategy was brought back recently in this Sept. 2017 thread.
It acknowledges older (2008) threads

In short, the previous discussion can be summarized to "we don't want '-s theirs' as it encourages the wrong workflow".

It mentions the alias:

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

Yaroslav Halchenko tries to advocate once more for that strategy, but Junio C. Hamano adds:

The reason why ours and theirs are not symmetric is because you are you and not them---the control and ownership of our history and their history is not symmetric.

Once you decide that their history is the mainline, you'd rather want to treat your line of development as a side branch and make a merge in that direction, i.e. the first parent of the resulting merge is a commit on their history and the second parent is the last bad one of your history. So you would end up using "checkout their-history && merge -s ours your-history" to keep the first-parenthood sensible.

And at that point, use of "-s ours" is no longer a workaround for lack of "-s theirs".
It is a proper part of the desired semantics, i.e. from the point of view of the surviving canonical history line, you want to preserve what it did, nullifying what the other line of history did.

Junio adds, as commented by Mike Beaton:

git merge -s ours <their-ref> effectively says 'mark commits made up to <their-ref> on their branch as commits to be permanently ignored';
and this matters because, if you subsequently merge from later states of their branch, their later changes will be brought in without the ignored changes ever being brought in.

于 2017-10-14T06:19:37.117 に答える
8

マージしているブランチからの入力のみを取得するマージを本当に適切に行うには、次のことができます。

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

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

git commit --amend

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

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

于 2013-10-30T14:47:43.637 に答える
6

Junio Hamano の広く引用されている回答を参照してください。コミットされたコンテンツを破棄する場合は、単にコミットを破棄するか、少なくとも主要な履歴から除外してください。何も提供するものがないコミットからのコミットメッセージを将来誰もが読むのを邪魔するのはなぜですか?

ただし、管理上の要件やその他の理由がある場合もあります。何も貢献しないコミットを本当に記録しなければならない状況では、次のことが必要です。

(編集:うわー、私は以前にこれを間違えましたか。これは機能します。)

git update-ref HEAD $(
        git commit-tree -m 'completely superseding with branchB content' \
                        -p HEAD -p branchB    branchB:
)
git reset --hard
于 2013-05-13T15:48:20.233 に答える
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>
于 2015-04-22T19:18:40.450 に答える
1

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

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

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

于 2016-08-31T13:41:17.160 に答える
1

この回答は 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
于 2019-05-29T21:17:52.603 に答える
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
于 2013-01-28T12:35:03.217 に答える
-1

シンプルで直感的な(私の意見では)それを行う2段階の方法は

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

に続く

git merge -s ours branchB

(2 つのブランチがマージされたものとしてマークされます)

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

このアプローチにより、その後の改訂ログから、何が行われ、何が意図されたかが明確になります。

于 2018-10-05T06:44:35.623 に答える