強制的な上書きによるGitマージ


100

私はブランチとdemoマージする必要があると呼ばれるブランチを持っていmasterます。私は次のコマンドで望ましい結果を得ることができます:

git pull origin demo
git checkout master
git pull origin master
git merge demo
git push origin master

私の唯一の懸念は、マージの問題がある場合、マージのプロンプトを表示せずgitmasterブランチの変更を上書きするように伝えたいことです。したがって、基本的にdemoブランチの変更は、ブランチの変更を自動的に上書きするはずmasterです。

私はいくつかのオプションがあるのを見て回りましたが、マージのチャンスを取りたくありません。


git push -f origin master
MD XF

4
@MDXF:私は間違っているかもしれないが、私は使用してはならない-fとのオプションをmerge指定して、コマンドではなくpush、コマンド
OpenStackの

あなたは両方を試してみて、あなたにとって何がうまくいくかを見ることができます
MD XF

力の上書きの解決のためにリンクの下を参照してください:stackoverflow.com/a/42454737/984471
ManoharさんレディPoreddy

回答:


98

この回答とはあまり関係ありませんがgit pull、を実行し、git fetchその後にを実行しgit mergeます。1つのフェッチで十分な場合、3つのマージを実行して、Gitに3つのフェッチ操作を実行させます。したがって:

git fetch origin   # update all our origin/* remote-tracking branches

git checkout demo         # if needed -- your example assumes you're on it
git merge origin/demo     # if needed -- see below

git checkout master
git merge origin/master

git merge -X theirs demo   # but see below

git push origin master     # again, see below

最も扱いにくいマージを制御する

ここで最も興味深い部分はgit merge -X theirsです。以下のようroot545は指摘し-Xオプションをマージ戦略、およびデフォルトの両方に渡されrecursive戦略や代替resolve戦略テイク-X ours-X theirs(どちらか一方、両方ではありません)。ただし、Gitが何を行うかを理解するには、Gitがどのようにして競合を見つけて処理し、マージするかを知る必要があります。

マージ競合は、いくつかのファイル内で発生することができる1際にベースの両方からのバージョンが異なる電流が(ローカル、HEAD、または呼び出された--oursバージョン)(また、リモートまたは呼ばれる他の--theirsその同じファイルの)バージョン。つまり、マージは3つのリビジョン(3つのコミット)、base、ours、およびtheirsを識別しました。「ベース」バージョンは、コミットグラフにあるように、コミットとコミットの間のマージベースからのものです(これの詳細については、他のStackOverflowの投稿を参照してください)。その後、Gitは「私たちがしたこと」と「彼らがしたこと」の2つの変更セットを見つけました。これらの変更は、(一般的に)行ごとに、純粋にテキストで見られます基礎。Gitはファイルの内容を実際に理解していません。テキストの各行を比較するだけです。

これらの変更はgit diff出力に表示されるものであり、いつものように、それらにもコンテキストがあります。私たちが変更したものは、変更したものとは異なる行にある可能性があります。そのため、変更は衝突しないように見えますが、コンテキストも変更されています(たとえば、変更がファイルの上部または下部に近いため)私たちのバージョンではファイルが不足しますが、彼らのバージョンでは、上部または下部にテキストが追加されています)。

変更がで発生した場合異なるライン-のインスタンス、我々は変更colorcolourライン17上で、彼らは変更fredbarneyライン上の71-その後、競合はありません:Gitは単に取り、両方の変更を。変更が同じ行で発生しても、同一の変更である場合、Gitは変更のコピー1つ取得します。変更が同じ行にあるが、異なる変更である場合、またはコンテキストが干渉する特殊なケースである場合のみ、変更/変更の競合が発生します。

-X oursそして-X theirs私たち、あるいは彼らを:オプションは、ちょうど2つの変更のいずれかを選ぶことによって、この競合を解決する方法をGitリポジトリを教えてください。demo(自分たちの)をmaster(私たちの)にマージしていてdemo、からの変更を望んでいると言ったので、あなたはを望み-X theirsます。

-Xただし、盲目的に適用することは危険です。変更が行ごとに競合しなかったからといって、変更が実際に競合しなかったわけではありません。古典的な例の1つは、変数宣言を持つ言語で発生します。基本バージョンは未使用の変数を宣言するかもしれません:

int i;

このバージョンでは、未使用の変数を削除して、コンパイラの警告を取り除きます。バージョンではi、ループカウンターとして使用して、数行後にループを追加します。2つの変更を組み合わせると、結果のコードはコンパイルできなくなります。-X変更が別の行にあるため、このオプションは役に立ちません。

自動テストスイートがある場合、最も重要なことは、マージ後にテストを実行することです。これはコミット後に行うことができ、必要に応じて後で修正できます。または、コマンドに追加することで、コミットする前にそれを行うことができます。このすべての詳細は他の投稿に任せます。--no-commitgit merge


1また、「ファイル全体」の操作に関して競合が発生する可能性もあります。たとえば、ファイル内の単語のスペルを修正し(変更を加えるため)、ファイル全体を削除します(そのため、削除)。Gitは、-X引数に関係なく、これらの競合を単独で解決することはありません。


より少ないマージを行う、および/またはよりスマートなマージを行う、および/またはリベースを使用する

どちらのコマンドシーケンスにも3つのマージがあります。1つ目はorigin/demo、ローカルに取り込むことdemoです(git pullGitが非常に古い場合、アップデートは失敗しますorigin/demoが、同じ最終結果が生成されます)。2つ目は、にorigin/master取り込むことmasterです。

誰が更新demoしているのか、および/または私が明確ではありませんmaster。あなたがあなた自身のdemoブランチであなた自身のコードを書いていて、そして他の人がコードを書いてそれをdemoブランチにプッシュしているなら、originこの最初のステップのマージは衝突するかもしれません、あるいは実際のマージを生成するかもしれません。多くの場合、作業を組み合わせるにはマージではなくリベースを使用する方が良いです(確かに、これは好みと意見の問題です)。その場合は、git rebase代わりに使用することができます。一方、自分でコミットをdemoまったく行わない場合demoブランチも必要ありません。あるいは、これの多くを自動化したいが、あなたと他の両方が行ったコミットがあるときに慎重にチェックできる場合は、git merge --ff-only origin/demo:これにより、可能な場合demoは更新されたものと一致するように早送りされorigin/demo、そうでない場合は完全に失敗します(この時点で、2つの変更セットを検査し、必要に応じて実際のマージまたはリベースを選択できます)。

これと同じロジックがに適用されmasterますが、でマージ 実行しているmasterため、間違いなくが必要masterです。ただし、早送りの非マージとして実行できない場合にマージを失敗させるのは、より可能性が高いため、おそらくこれもそうgit merge --ff-only origin/masterです。

あなたが自分でコミットをすることは決してないとしましょうdemo。この場合、名前をdemo完全に破棄できます。

git fetch origin   # update origin/*

git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"

git merge -X theirs origin/demo || die "complex merge conflict"

git push origin master

あなたがいる場合しているあなた自身のやってdemo分岐コミットを、これは便利ではありません。既存のマージを維持する(ただし--ff-only、必要な動作に応じて追加する)か、リベースを実行するように切り替えることもできます。マージが競合して失敗することがあり、とのマージは:すべての3つの方法が失敗する可能性があることに注意--ff-only早送りできないことがあり、そしてリベースは、紛争(リベースは本質的に、ことによって動作し、で失敗することがありさくらんぼ狩りマージを使用してコミット、機械、したがってマージの競合が発生する可能性があります。


19

同様の問題があり、変更があったファイルや別のブランチと競合しているファイルを効果的に置き換える必要がありました。

私が見つけた解決策は使用することgit merge -s ours branchでした。

オプションはで-sあり、でないことに注意してください-X。トップレベルのマージ戦略として-sのの使用を示し、oursマージ戦略にオプションを-X適用することになりoursますが、recursiveこの場合は私(または私たち)が望んでいることではありません。

手順。oldbranchは、で上書きするブランチですnewbranch

  • git checkout newbranch 保持したいブランチをチェックアウトします
  • git merge -s ours oldbranch 古いブランチにマージしますが、すべてのファイルを保持します。
  • git checkout oldbranch 上書きしたいブランチをチェックアウトします
  • get merge newbranch 新しいブランチにマージし、古いブランチを上書きします

注:ここでは他の解決策はどれもうまくいきませんでした。そのため、私の答えを投稿します。
Niall Mccormack

1
うまくいきませんでした。競合は解決されましたが(競合するファイルが解決されました)、ファイルはマージされません。どちらもマージできません。
c-an

「このマージが必要な理由を説明するためにコミットメッセージを入力してください」というプロンプトが表示されて誰かが行き詰まった場合:メッセージを入力してから、キーボードのEscキーを押し、:wqと入力してEnterキーを押し、プロンプトを終了します。
topherPedersen

17

このマージアプローチmasterは、feature競合やその他のがらくたについて文句を言わずに、1つのコミットを追加し、その上に何でも貼り付けます。

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

何かに触れる前に

git stash
git status # if anything shows up here, move it to your desktop

今マスターを準備

git checkout master
git pull # if there is a problem in this step, it is outside the scope of this answer

取得featureすべてのドレスアップ

git checkout feature
git merge --strategy=ours master

殺しに行く

git checkout master
git merge --no-ff feature

1
git pushで終了
Kochchy

git-scm.com/docs/git-merge#Documentation/git-merge.txt-ours。コミットがきれいにマージされていないときに機能しました。しかし、このアプローチは、ソースを引用するために常に機能するとは限りませんChanges from the other tree that do not conflict with our side are reflected in the merge result。上書きされていた私のブランチでコミットをきれいにマージしていたので、私にはうまくいきませんでした。他に方法はありますか?
NiharGht

11

git mergeで「ours」オプションを試すことができます。

gitマージブランチ-X私たちのもの

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


3
OP demoがにマージしている場合でもバージョンを優先することを望んでいるので、これは逆masterです。そこにもありますが-X theirs、これがOPが本当に望んでいることかどうかは明らかではありません。
torek 2016年

全文を読んでいない。あなたのノートはours-sオプション付きのバックエンドで使用するときに何が行われるかを説明しています。oursとともに使用する場合-X他のツリーが行ったすべてのことを破棄し、履歴にその中で発生したすべてのものが含まれていることを宣言します。 出典
jimasun 2017

2

-X theirs他の関連するコマンドスイッチを使用してみたところ、マージコミットが発生し続けました。私はそれを正しく理解していなかったのでしょう。理解しやすい代替策の1つは、ブランチを削除してからもう一度追跡することです。

git branch -D <branch-name>
git branch --track <branch-name> origin/<branch-name>

これはまさに「マージ」ではありませんが、これは私がこの質問に出くわしたときに私が探していたものです。私の場合、強制的にプッシュされたリモートブランチから変更をプルしたいと思いました。

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