複雑なマージにどのようにアプローチしますか


25

ここに取引があります。私は新しい会社に入社し、ほとんど一年間触れられていないブランチの仕事を終えるように頼まれました。一方、マスターブランチは安定したペースで成長しています。masterブランチからのすべての変更をfeatureブランチにマージして、そこから作業を継続したいのが理想ですが、どのようにこれにアプローチするのかはよくわかりません。

ブランチの両側で重要な変更を保持しながら、このマージを安全に実行するにはどうすればよいですか?


素晴らしいフィードバックをありがとう。git-imergeを試してみますが、それが面倒な場合は、新しいブランチアプローチを使用します。
Vlad Spreys

なぜgit cherry-pickここで使用できないのかを説明できますか?
サントシュクマール

1.祈り。2.リベース。3.テスト。4.マージ。
AK_

1
コミットごとにコミットされるので、この状況でリベースすることを好みます。また、マージされたコードを使用可能にする前に、新しい機能を無効にすることもできます。YMMV。
スティーブン

回答:


27

基本的に、2つの(おそらく互換性のない)コードを組み合わせる方法は、バージョン管理の問題ではなく、開発の問題です。Gitマージコマンドはこのプロセスに役立つ場合がありますが、問題の形状によって異なります。

最初に両方のバージョンをベースと比較するのが最も理にかなっています。これにより、これを進めるための最適な戦略がわかります。アプローチは、各ブランチの変更の性質と重複に基づいて異なる場合があります。

理想的なシナリオを想像してください。メインブランチと機能ブランチはそれぞれコードの相互に排他的な部分を変更するだけであるため、すべての変更をコミットしてそのまま実行できます。

もちろん、それはほとんど間違いなくそうではありませんが、問題は次のとおりです。この理想的なシナリオからどれだけ離れているか。つまり、変更はどの程度混在していますか?

また、古い機能ブランチはどれくらい成熟していましたか?それは良い動作状態にあったのか、そうでないのか(または不明)どのくらいの機能が終了しましたか?

メインブランチの関連コードが過去1年で大幅に変更された場合、または機能があまり成熟していない場合は、最新の新しいフォークを作成し、古い機能を再度手動で組み込むことを検討できます。 これにより、それを機能させるための漸進的なアプローチが可能になります。

大量のコードを乱雑にマージしても機能しない場合、デバッグするのは非常に困難です。メインブランチが過去1年間で大きく変更された場合、機能を機能させるには、機能に大きな設計変更が必要になる場合があります。「競合の解決」を介してこれらの変更を行うことは適切ではありません。すべての変更を一度に行い、それが機能することを期待する必要があるためです。この問題は、部分的に終了した古いブランチのバグの可能性によってさらに悪化します。


+1「最新の新しいフォークを作成し、古い機能を手動で再度組み込むことを検討するかもしれません」
ミカ

1
最初の重要な質問は、古い機能ブランチはビルドされますか?実行しますか?そうでない場合、マージをテストするのは非常に困難になります。
モー

22

私の限られたgitの経験では、マスターがデタッチポイントから離れすぎた場合、機能ブランチを再起動する方が速い場合があります。

コードの背後にある歴史を知らずに2つのブランチをマージすることは(プロジェクトに参加したばかりだとして)本当に困難であり、プロジェクトを最初からフォローしていた開発者でさえ、マージで間違いを犯す可能性が高いと思います。

もちろん、機能ブランチがそれほど大きくない場合、これは理にかなっていますが、古い機能ブランチを開いたままにして、マスターから再び分岐し、その機能を構成する変更手動で再導入することができます。私はそれが最も手作業のアプローチであることを知っていますが、それはコードの欠落や移動の場合に完全に制御できるようにします。

この場合、シニアとペアプログラミングするのが最良のシナリオであり、コードをよりよく理解するのに役立ちます。
マージの競合とテスト時間を考慮すると、さらに高速になることさえあります!

少なくともマージを試みることは明らかに最善のことだと思います。それが失敗するか、難しすぎると判明した場合は、チェリーピッキングを試してください。それがうまくいかない場合は、手動で行ってください。


2
間違いなく正しいアプローチではありません。
アンディ

12
いいえ、これは正しいアプローチです-古代のブランチがあり、コードがわからない場合、マージしようとすることはあまり成功せず、非常に危険です。元々行われた変更を特定し、それらが新しいコードに関連するかどうかを調査し、それを意味のあるものに適用することが、その方法です。これは手動のアプローチですが、このような状況では、唯一安全な方法です。もちろん、何が起こるかを見るためだけに、最初にマージを試みます。また、ブランチでどの程度の変更が発生したかをログで確認します-些細なことかもしれません。
gbjbaanb

10
@DavidPacker:GavianoGrifoniがすべての作業を船外に投げることを提案しているとは思わない。彼は、変更を古いブランチから現在の開発ラインに段階的に手動で転送することを提案します。それは古い歴史を捨て去るでしょう。
Doc Brown

3
@DavidPacker 1番目:ブランチは1年古いです、2番目:終了を任された人はコードをまったく知りません。これらの2つの要因を考えると、手動で再適用することがタスクにアプローチする唯一の現実的な方法です。古いブランチのチップリビジョンの単純なコピーペーストを提案する人はいません。
gbjbaanb

5
@DavidPacker:マージの競合は悪になる可能性があります-プログラムをコンパイル可能かつテスト可能な状態に戻す前に一度に500個の競合を解決する必要がある場合。これが、OPがここで期待しているような状況です。gitを効率的な方法で使用して、この「オールオアナッシング」状況を回避できると考えている場合は、回答を編集してOPにこれを達成する方法を教えてください。
ドックブラウン

16

git-imergeはまさにこの目的のために設計されています。インクリメンタルマージの方法を提供するgitツールです。インクリメンタルにマージすることにより、2つのバージョン間の衝突のみを処理する必要があり、それ以上は処理しません。さらに、個々のチェンジセットが小さいため、はるかに多くのマージを自動的に実行できます。


6

メインラインヘッドを1年前の古いブランチにマージしようとすると、欲求不満が生じ、額にデスクのへこみが深くなることがあります。

メインラインは、数か月の間に一回で目的地に到達しませんでした。開発とリリースもありました。1つのモノリシックマージですべてを最新の状態にしようとすると、圧倒されます。

代わりに、古いブランチが分割された後、最初の機能マージからメインラインにマージすることから始めます。取得そのマージ作業を。次に、次の機能のマージ。等々。これらの機能のマージの多くは、競合することなくマージされます。古いブランチの現在の機能がメインラインが行った方向と互換性を保つことを確認することは依然として重要です。

他の変更にマージする役割のために、古いブランチのヘッドからブランチすることをお勧めします。これは、誰かがそれを振り返ったときのコミットと履歴を明確にし、各ブランチの役割とポリシーを明確にすることです。古いブランチは機能ブランチでした。あなたが働いているのは、蓄積と和解のブランチです。

古い機能またはリリースブランチがまだ存在し、簡単にアクセスできる場合、これの多くは簡単です(一部の場所には、ブランチのリストが圧倒されないように、ある日付より古いブランチの名前をクリーンアップするポリシーがあります)。

このすべてで重要なことは、メインラインの履歴の各部分を適切にマージした後、テストして修正することを確認することです。競合なしで何かがマージされる場合でも、それは単にコードが競合しなかったことを意味します。古い機能へのアクセス方法が非推奨または削除された場合、マージの成功後に修正が必要になる場合があります。

余談ですが、これは他のバージョン管理システムでも機能します。特定のsvnコミットのグループを1つの機能のブランチ(チェリーピッキング)にマージし、その機能で動作するようにブランチを修正してから、単にsvnコミットを実行するのではなく、次のsvnコミットのグループをマージする必要が時々ありましたマージ。

1の間にできるのgitここチェリー選ぶ行い、それが中に持ち込むことができない特定のコミット、これは、プロセスを複雑にする可能性があるいくつかの欠点があります。チェリーピックには、選択したコミットに関する情報は表示されません(コミットメッセージに追加できます)。これにより、履歴内のコミットを実際に追跡するのが難しくなります。

さらに、マスターを古いブランチに効果的にリプレイしないことを意味します-不完全な機能を選択することになります-そして、それらの機能は順不同で再生される可能性があります。

過去のコミットからマスターへの古いブランチへのマージが必要な主な理由は、それを保持できるようにすることです。履歴から古いブランチへのマージと、機能を再統合するための修正を明確に見ることができます。機能は、マスターするのと同じ順序で追加されています。そして、完了し、最後にマスターのヘッドから古いブランチへのマージを行うと、すべてがマージされ、コミットが欠落していないことがわかります。


+1これは、マージを使用して大きな変更を組み込む興味深い潜在的な代替ソリューションです。しかし、マイナス面を見ることができます:メジャーバージョンABCDEがあり、機能ブランチA1をEに組み込みたいとします。BCとDにコードをマージする多くの無駄な努力があるかもしれません。 B、C、Dのインクリメンタルな変更を無関係にした大きな設計変更ですか?また、そもそも機能がどれだけ成熟しているかにもよります。有用な潜在的アプローチですが、開始する前にその適切性を考慮する必要があります。

1

ステップ1.コードについて学び、そのアーキテクチャを分析し、最新の共通の祖先以降に両方のブランチで行われた変更を分析します。

ステップ2.機能が広く独立しているように見え、主にコードのさまざまな領域に触れている場合、マージ、競合の修正、テスト、修正など。これが幸せな道です。それ以外の場合は、ステップ3に進みます

ステップ3.競合する領域を分析し、機能的な影響と理由を詳細に理解します。ここで明らかになるビジネス要件の競合が容易に発生する可能性があります。必要に応じて、他の開発者とBAと話し合ってください。干渉の解決に伴う複雑さを感じてください。

ステップ4.上記を考慮して、競合しない部分のみをマージ/チェリーピック/カットアンドペーストして、競合する部分を書き直すか、機能全体を最初から書き直すかを決定します。 。


0

1.メインの開発者/リリースブランチとして使用されるブランチに切り替えます。

これは、システムに対する最新の変更を含むブランチです。することができmastercoredev、それは会社によって異なります。あなたの場合、おそらくmaster直接です。

git checkout master
git pull

メインの開発ブランチの最新バージョンを取得していることを確認してください。

2.終了することになっている作業を含むブランチをチェックアウトしてプルします。

実際にブランチの最新のコンテンツを持っていることを確認するためにプルします。最初にローカルで作成せずに直接チェックアウトすることで、新しいコンテンツmaster(またはそれぞれメインのdevブランチ)が含まれないようにします。

git checkout <name of the obsolete branch>
git pull origin <name of the obsolete branch>

3.メインの開発ブランチを廃止されたブランチにマージします。

次のコマンドを実行する前に、入力するgit branchgit status、古いブランチにいることを確認してください。

git merge master

このgit mergeコマンドは、指定されたブランチ(この場合は)の内容をmaster現在のブランチにマージしようとします。

重視しようとします。マージの競合が発生する可能性がありますが、それはあなたとあなただけが解決する必要があります。

4.マージの競合を修正し、コミットして競合の修正をプッシュする

存在するすべてのファイルのマージ競合を修正した後、競合解決をステージング、コミット、およびプッシュしoriginます。

git add .
git commit -m "fixed the merge conflict from the past year to update the branch"
git push

通常git add .、すべてのファイルをコミット用にステージングするために呼び出すことができます。マージの競合を処理する場合、必要なすべてのファイルを更新する必要があります。

追加メモ

マージの競合を解決するのは退屈な作業です。特にあなたが会社で新しい場合。マージの競合をすべて単独で解決するための適切な知識さえないかもしれません。

作業を続行する前に、発生したすべての競合を注意深く調べて適切に修正するために時間をかけてください。


そのため、1年前のブランチで作業を開始し、現在の開発状態をそこにマージすると、マージの競合がまったくなくなります。

これは、システムが一年で大きく変化したにもかかわらず、1年前のブランチで実際に変更されたファイルに誰も触れていないときに起こります。


6
#4が潜在的に問題です。昨年にわたって多くの変更があった場合、古い機能に大きな変更が必要になる場合があります。マージによりこれを行うには、コードを大幅に変更する必要があり、一度にすべてを実行し、それが機能することを期待しますが、これは良い開発プラクティスではありません。さらに、未完成の機能の状態を誰が知っているのでしょうか?動作しないコードが大量に発生する可能性がありますが、それが元の問題によるものなのか、変更によるものなのかを誰が知っているのでしょうか?

デビッド、この標準的なアプローチが機能する限り、それは問題なく、OPは最初にこれを試すべきです。しかし、この「オールオアナッシング」の方法でそれらを処理するには、説明した状況でマージ競合が多すぎるというリスクが確実にあります。
Doc Brown

@ dan1111マージの競合があることは完全に問題ありません。実際、それらを通過することが道です。ブランチは1年間そのままでしたので、それはそれほど重要ではなく、システムの多くに影響を与えないことを確信できます。そのため、ブランチは1年遅れていますが、マージ競合は2から0になります。
アンディ

4
このブランチが重要でないという仮定は保証されません。それは放棄され、現在再び取り上げられている根本的な設計変更である可能性があります。それは何でもかまいません。あなたはそれ簡単な問題であり、競合がほとんどまたはまったくない可能性があることは正しいです-その場合、あなたの答えは正しいでしょう。しかし、それが唯一の可能性ではありません。

@ dan1111誰かが別のブランチの機能の場所に1年間触れなかった場合、システムの変更をそれほど反映しません。これは、廃止された(6か月以上前の)ブランチでの私自身の経験から来ています。
アンディ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.