web-dev-qa-db-ja.com

熟練した開発者はまだマージの競合に対処する必要がありますか?

私はまだトレーニングのソフトウェアエンジニアですが、次の格言を何度も聞いています。

優れたコーダーはマージの競合に対処する必要はありません。

他の人と一緒にプロジェクトに取り組むときはいつでも、マージの競合を解決するための煩わしい時間と労力を失っています。だから、私はその格言がどれほど本当であるか疑問に思い始めました。 GitFlowやアジャイルのように、開発者が作業を効率的に分割し、より頻繁にコミットし、コードの複数のブランチを維持できるテクニックを知っているので、マージの競合はほとんど起こりません。しかし、確かにそれらはまだ起こり、大混乱を引き起こす可能性がありますか?

言い換えれば、経験豊富な開発者は、(プロジェクトに取り組んでいる可能性がある場合)マージの競合を解決するためにどれだけの時間と労力を費やすのでしょうか。マージの競合の影響を実際に打ち消すことができる利用可能なテクニックはありますか?

57
lemeneux

良い開発者がマージの競合を起こしたことは決してないと言うのは少し不誠実だと思いますが、確実に発生する回数を減らすことができます。ソフトウェア開発はチーム活動であることを覚えておくことも非常に重要です。チームの他のメンバーのアクションも、マージの競合の可能性を増加または減少させる可能性があります。

まず、マージの競合が発生する一般的な方法を理解することが重要です。

  • 2人が同じコード行に異なる変更を加える
  • 誰かがすべての行が変更されるようにファイル全体を再フォーマットすることにしました
  • ファイルを削除してから置き換える(これはツリーの競合です)
  • コードは2人の異なるユーザーによって同時に削除および追加されます(Visual Studioでは珍しくありません.vsprojファイル)

開発teamsはこれらの状況を回避する方法を考え出しました:

  • 各チームメンバーがコードの異なる部分で作業している(つまり、タスク割り当てで処理されている)ことを確認します。
  • スペースまたはタブを使用するかどうかを指示するコード標準、命名標準などにより、販売全体のコードの再フォーマットが不要になります。
  • GitFlowにより、全員が自分のブランチで作業し、プルリクエストステージで競合を解決できます(すべてのダウンストリームマージがうまく機能します)。
  • 機能ブランチが古くなりすぎないようにするために、開発からマージして頻繁に定期的にコミットする
  • 機能が1〜3日で実行できるほど小さいことを確認します。

このような変更により、競合の可能性を大幅に最小限に抑えることができます。それらを完全に排除することはできません。

97
Berin Loritsch

おそらく引用は不完全です:

優れたコーダーはマージの競合に対処する必要はありません...
...優れたコーディング担当者が力を押すため。

ただし、真剣に、マージの競合を回避する唯一の方法は、単独で作業することです(それでも役に立たない;個人的なプロジェクトで自分とマージの競合が発生しました)。ただし、経験豊富な開発者を雇う会社では、マージ競合の痛みを軽減する3つの要因があります。

  1. チーム内の優れたコミュニケーション。

    つまり、あなたは同僚が何に取り組んでいるのかを知っており、彼らはあなたが何をしているかを知っています。したがって、チームの誰かが作業している領域を変更する可能性がある場合は、尋ねます(または伝えます)。このようにして、苦痛なコミットのリスクを大幅に減らします。

    これは特に、コードベースの大部分に大きな影響を与えたり、マージが困難な変更を行ったりするリファクタリングタスクに当てはまります。たとえば、同僚がこの変数を使用する機能を実装しているときに、特定の変数の型をどこでも変更しているとします。マージの衝突が発生するリスクがあるだけでなく、マージ中にビルドが中断するリスクもあります。

  2. 素晴らしいアーキテクチャ。

    4K-LOCファイルを含むレガシーコードベースで作業していて、何十ものファイルを変更するための基本的な変更が必要な場合は、変更のたびにマージの競合が発生する可能性があります。

    一方、アーキテクチャが十分な場合は、(1)インターフェイスを変更する場合、または(2)2人の同僚がアプリケーションのまったく同じ部分を変更する場合の2つの状況にマージの競合が発生するリスクを軽減します。 。最初のケースでは、コミュニケーションをとることで、面倒なマージのリスクをさらに減らします。 2番目のケースでは、ペアプログラミングを行い、マージを完全に削除します。

  3. 他のチームとの適切なインターフェース。

    ときどき、異なるチーム間でマージの競合が発生することがあります。あるチームがモジュールを変更していて、別のチームがこのモジュールを使用するコードを変更しているとします。

    経験豊富な開発者は、システムの個別の部分をより技術的に独立させるSOAなどの適切なインターフェースを採用する傾向があります。さらに、他の人のコードを直接変更することを避けるために、Pushリクエストなどの特定のプラクティスにはるかに依存します。

    これは基本的に最初の2つのポイントですが、チームを超えたコミュニケーションを実現し、パーツの混合を確実にします。

27

ある同僚が、マージの競合に対処する必要のない開発者に遭遇しました。

彼はいくつかの変更を加え、それらをマージし、数日後に変更は消えました。彼は、別の大陸にいる他の誰かが、マージする代わりにファイルを置き換えたことを発見しました。

彼は変更を元に戻し、わずかに差分を付けました-数日後、変更は再びなくなりました。

それは彼が彼のマネージャーと長い話し合いをしたときであり、それは順番に他のチームのマネージャーと長い話し合いをしました、そしてそれは身体的暴力の脅威を含んでいるかもしなかったかもしれません、そして他のチームのマネージャーは明らかに開発者と長い話し合いを持っていました質問、そして行動が停止しました。

とはいえ、経験豊富な開発者はマージの競合を回避できます。

  1. ファイルの名前を変更するときは、1つのマージを実行します。ファイル名の変更(および、これによって引き起こされる変更(インクルードステートメントやプロジェクトファイルの変更など)のみ)が唯一の変更です。

  2. コードを見ただけで変更を加えないように、全員のエディター設定が同じであることを確認してください。

  3. 2人がコードを変更するとマージの競合が発生します同じ場所で。したがって、ファイルに追加する場合は、最後に追加するのではなく、論理的に正しい場所に追加してください。そうすれば、別の開発者が同じことをした場合、マージの競合が発生する可能性ははるかに低くなります。

  4. manyマージの競合が発生しないように、共通コードベースをブランチにマージしてください。 1つの競合は簡単です。1つのマージで10が問題です。

  5. ブランチから共通コードベースにマージすると、競合が発生しますnever。 (4)マージしようとする直前に行ったので、マージは変更なしでコードを取得することになります。

ちょうど気づいた:はい、それは本当です、優れた開発者はブランチから共通のコードベースにマージするマージ競合を決して持っていません。マージの競合は以前に処理されているためです。

21
gnasher729

他の回答で述べたように、マージの競合は経験やスキルに関係なく発生し、スキルの不足が原因である種の弱点であると主張する格言はばかげています。

他の回答では、熟練した開発者がフォーマットの混乱の防止から頻繁なマージまで、チームの調整を改善するために、マージの競合を少なくする方法を学ぶことができますが、あなたが提起するより広い概念にはいくつかの真実があると思います:熟練した開発者はより上手になることができますマージの競合が発生した場合の対処。

マージの競合を解決するのは難しいです。競合を見つけ、競合マーカーを理解し、コードのコンテキストを考慮して両側で何が変更されたかを把握する必要があります(おそらくフォーマットなどの特定が難しい問題が含まれます)、おそらくマージの両側から個々のコミットを調べます元の意図を理解し、実際に競合を解決し、コードベースの他の場所(またはAPIまたはインターフェースが関係する場合は他のリポジトリーでも)の変更が及ぼす可能性のある影響に対処し、コンパイル、テスト、コミットなどを行う...このプロセス中にバージョン管理システムに必要な処理を実行させます。そして、より複雑なケースがあります:移動/削除されたファイルとディレクトリを含む競合。バイナリファイルを含む競合。生成されたファイルに関連する競合(Visual StudioやXcode構成ファイルなどを含みます。競合が単純であっても、ある程度の経験があるまで、ファイル自体はなじみがありません)。マージの反対側にいる人を見つけて一緒に理解するのに十分厄介な競合。あらゆる種類の楽しみ。

それはすべて対処すべき多くのことです。それは少しパニックを引き起こす可能性があります。何かをまとめるために興奮して一緒にクルージングしていて、突然あなたはファイルの真ん中にエラーメッセージ、奇妙な ">>>>>>>"ものに直面し、そしてどこかから突然現れた見慣れないコードの束。他のプログラミングタスクと同様に、経験はそれをより効率的かつ苦痛なく処理するスキルの構築に役立ちます。初めてマージの競合が発生した場合、それは混乱を招く試練ですが、500回目はより日常的です。この時点で:

  • バージョン管理システムを使用して、必要な情報を取得し、必要な変更を加えることができます。
  • 競合の形式、差分の読み取り、マージの変更の視覚化について理解している。
  • あなたは マージを支援するためのツール、オープンソース、またはコマーシャル を入手し、それらを効果的に使用する方法を学んだかもしれません。これらは非常に役立ちますので、太字で示します:優れたツールは、マージの競合を大幅に軽減するのに役立ちます
  • プロジェクトで一般的な種類の競合(IDE構成ファイル、文字列ファイルの下部、頻繁に変更されるその他のホットスポット)を知っており、プロセスを調整してそれらを防止するか、それらを本当に迅速に解決することに慣れます。 「ああ、どちらもファイルの最後に新しい文字列を追加した」などの一般的な競合は、簡単に修正できます。
  • どのタイプのリファクタリングタスクがチームの他のメンバーとの競合を引き起こす可能性が高いかを予測し、痛みを軽減するように調整できます。
  • いつマージしないのか知っています。マージを試みて、他の誰かが削除した関数にパラメーターを追加したことがわかった場合は、戦略を停止して、競合解決プロセスの範囲外で戦略を再検討することをお勧めします。
  • 実際に混乱したことがわかったら、マージをやり直すのが簡単になります。
  • 基盤となるコードベースの変更が多すぎて、実行していることの「説明」を公平に説明できない場合は、実際に加えたい変更を書き留め、変更を破棄して、新しいクリーンなHEADからやり直します。たとえば、変更が新しい画像ファイルを追加することだけであり、その間に誰かがやって来て、プロジェクトのすべての画像をスプライトにした場合、実際には、別の方法でタスクを実行するほどマージすることはありません。だからあなたの以前の努力を吹き飛ばして、それを新しい方法でやってください。

これにより、ほとんどのマージ競合は日常的なものになるため、それらの処理に費やす時間と労力は少なくなります。それらは依然として発生し、時々重大なフラストレーションを引き起こしますが、通常、混乱ははるかに少なくなります。

6
Zach Lipton

マージ競合の存在ではなく、それらが引き起こす問題の程度です。

未経験の開発者とのマージの衝突による「ダメージ」は大きな問題であると見られています。人々は、これらの「大規模な」問題を回避するために、クレイジーなソース管理スキームを発明したり、ソース管理の使用をすべて停止したりします。

しかし、経験豊富なチームでは、マージの競合はほとんど問題を引き起こさず、迅速に解決されます。

これに寄与するアプローチには、主に2つの違いがあると思います。

  1. ソース管理を適切に使用する。機能ブランチ、たくさんの小さなコミット、プッシュ前のプル、プッシュ前のテストなど。

  2. 他の人々の変化を理解する。変更と競合した機能とコードの変更を理解していれば、2つをマージするのは簡単です。

スタンドアップでの他のタスクに注意を払い、彼らがどのように変更を実装しているか、どこで競合する可能性があるかについて他の人と話します。物事がどのように機能するかを事前に合意します。

5
Ewan

継続的統合

CIがマージの競合を経験するためには、そのブランチの変更がマスター上の1つ以上の変更と競合する必要があると考える理由を理解するために、次のようにします。

             A  B  C
master    *--*--*--*--*
           \         /
feature-x   *--------

ブランチに存在する時間が長いほど、マスターで行われる変更が多くなるため、それらの変更の1つが競合を引き起こす可能性が高くなります(ブランチの変更が非常に小さい場合でも)。

             A  B  C  D  E  F  G  H
master    *--*--*--*--*--*--*--*--*--*
           \                        /
feature-x   *-----------------------

2つの変更が競合する可能性を低くするためにできることはさまざまです(再フォーマットを回避したり、複数の開発者が同じ領域で作業するのを避けるために作業を注意深く整理したりするなど)が、最も簡単な方法は、変更をより迅速にマージして削減することですマスターで行われた変更の数、および競合の可能性:

             A     B  C
master    *--*--*--*--*--*
           \   /    \   /
feature-x   *--      *--

CIを適切に実践している場合、全員が共有ブランチを1日に複数回、つまり数時間ごとにコミットする必要があります。これは、競合する変更はもちろんのこと、多くの場合マスターに変更が加えられないほど高速です。さらに良いことは、競合が発生した場合でも変更は少なくなるため、競合の解決は比較的簡単になるはずです-最悪の場合のシナリオ(変更を完全に破棄して再実装する必要がある場合)では、ほとんどの場合、数時間は働きます。


コメントでは、開発者は定期的にfromマスターをマスターにマージするのではなく、マージする必要があることが示唆されています。たとえば、次のグラフでは、マスター(A、B、C)の各コミットがブランチ(X、Y、またはZ)のコミットと競合する可能性があり、合計9つの潜在的な競合が発生します。最後に一度マスターにマージすると、9つの潜在的な競合すべてを同時に解決する必要があります。

             A  B  C
master    *--*--*--*--*
           \         /
feature     *--*--*--
            X  Y  Z

代わりに、マスターで変更するたびにマスターから機能ブランチにマージする場合:

             A     B     C
master    *--*-----*-----*---*
           \  \     \     \ /
feature     *--*--*--*--*--*
            X     Y     Z

次に、マージするたびに、次の競合に対処する必要があります。

  • 最初のマージでは、コミットAとXの間の競合を解決する必要があります
  • 2番目のマージでは、BとX、BとYの間の競合を解決します
  • 最後のマージでは、CとX、CとY、CとZの間の競合を解決します

ただし、変更Yが行われる前に変更Aが機能ブランチにマージされたため、AとYの間の競合を解決する必要はなかったことに注意してください。マスターから定期的にマージすることにより、合計で9つの潜在的なマージ競合のうち3つを回避することができました。

また、マージするたびに潜在的な競合の数が増加します-機能ブランチが存在する期間が長くなるほど、マスターで行われる変更(したがって潜在的な競合)が多くなりますが、本当のキラーは、機能ブランチで行う各変更です。マージするたびに潜在的な競合の数に相乗効果があります。

ここで、CIを練習していた場合に何が起こったかを考えてみましょう。

             A     B     C
master    *--*--*--*--*--*--*
           \   / \   / \   /
feature     *--   *--   *--
            X     Y     Z

今回は、次のマージ競合に対処する必要がありました。

  • 変更Xをマスターにマージするとき、AとXの間の競合を解決する必要がありました。
  • 変更Yをマージするとき、XとVの間の競合を解決する必要がありました
  • Zをマージするとき、ZとCの間の競合を解決する必要がありました

以前と同様に、変更Yを行う前に変更Aが機能ブランチに既にマージされているため、AとYの間の競合を解決する必要はありませんでしたが、今回は変更XとB、XとCをマージする必要もありませんでした。 、またはYとC、9つの潜在的な競合のうち6つを回避します。

マスターへの定期的なマージに関する詳細/ガイダンスについては、この質問を参照してください:

「頻繁に」マージするのが良いですか、それとも完了後にのみ機能ブランチの大きなマージを行うのですか?

1
Justin

「プログラマーは間違いを犯すいつも "--- John Carmack

「私は「ロックスター」開発者」または「優れたコーダーはマージの競合に対処する必要がない...」に似た主張をする人々は、一般的なソフトウェア開発コミュニティに豊富にいるように見えるposersよりも多いそのため、まとめて無視する必要があります。

自分以外の実在の人々が使用する本番環境で使用するソフトウェアを構築することは、簡単なことではありません。あなたは間違いを犯します...そして、あなたが一緒に働いている人々はしばしば間違いを犯します。マージコンフリクトに対処する必要があるかどうかに関するエンジニアリングコンピテンシーの評価に基づくことは、一見するとナンセンスです。

0
user405887

それが「良いコーダー」という特定の概念を念頭に置いて言っている人は誰でも、おそらく次のようになります。

  • Good Coderは、一人で設計したGreat Programで一人で作業します。
  • プログラムのフォークやリリースブランチなどはありません。そのため、競合を引き起こすリベースアクティビティはありません。
  • プログラムの古いリリースでバグが見つかった場合、ユーザーは現在のベースラインに忠実にアップグレードするか、ダウンストリームのパッケージメンテナーが現在のベースラインから必要な修正をバックポートします(したがって、Good Coderが関与する競合を確認することはありません)。
  • 一部の部外者がGreat Programの修正または拡張を提供するというまれなイベントでは、彼らは現在の開発ヘッドにクリーンに適用されるパッチを提供する必要があるため、Good Coderは競合解決を含む前方移植の取り組みから保護されます。
  • 最後に、Good Coderはコミットの順序を再配置することはありません(gitのインタラクティブなリベースなど)。
0
Kaz