最初に、マージがどのように機能し、ほとんどすべてのバージョン管理システムで機能するかについての簡単なレッスンです。
標準の Merge は3 方向のマージです。ここでは、2 つのバージョンを 2 つのバージョンの最後の共通の祖先と比較しています。たとえば、トランクから分岐します。ブランチの前のトランクのバージョンは、最後の共通の祖先です。
目的は、一方のストリームの変更と他方のストリームの変更を確認できるようにすることです。(ストリームは、特定のブランチまたはトランクである可能性があります)。たとえば、トランクからブランチにマージする場合、特定のブランチの変更をトランクのそれらの行で上書きしないようにしたいと考えています。
最後の共通の祖先と比較すると、その分岐点以降にトランクで発生した変更のみを確認できます。
これは、以前のマージからさかのぼるときに問題を引き起こします。たとえば、フィーチャー ブランチが完成したので、すべてのフィーチャーの変更をトランクに戻したいとします。トランクの変更をすべてブランチにマージしたため、これは問題です。つまり、ブランチのストリームは、ブランチに変更を加えたことを示しており、これらはトランクにマージする必要があります。しかし、これらの変更はすでにトランクにあります。この問題を処理するには、双方向のマージを強制できます。この場合、2 つの別々のストリームのヘッドを互いに比較し、1 つのストリームから別のストリームにすべての違いをコピーするだけです。
Subversion がマージを処理する方法:
まず、Subversion はチェリー ピック マージが大好きです。Subversion では、マージするリビジョンを指定できます。たとえば、ブランチがあり、バグを見つけてブランチで修正しました。バグ修正を含む特定のリビジョンまたはリビジョンのセットをマージできるようになりました。Subversion でチェリー ピックすると、3 方向のマージが行われますが、トランクまたはブランチのすべての変更ではなく、特定のチェリー ピックバージョンで表される変更のみが考慮されます。
実際、Subversion は、チェリー ピック リビジョンを指定しなくても、ほぼ常にチェリー ピック マージを行います。Subversion は、svn:mergeinfo
プロパティを介してどのリビジョンがマージされたかを追跡します。リビジョン 100 でブランチを作成し、トランクの変更をブランチにマージしているとします。トランクの最後のリビジョンは現在リビジョン 150 です。Subversion は、リビジョン 100 (ただし、バージョン 100 は含まれません) からリビジョン 150 までのトランクのすべてのバージョンのチェリー ピックを行っていると見なします。ブランチ (私のトランクの最後の変更が現在 175 であるとしましょう)、Subversion は(150 を含まない) 以降のトランクの変更をリビジョン 175 からチェリー ピックします。
マージにチェリー ピック リビジョンを指定すると、ブランチとトランクの間を問題なく行き来できることに注意してください。機能ブランチからトランクにマージする場合、機能を実装した機能ブランチのリビジョンを指定し、トランクからのマージの結果である機能ブランチの変更をスキップできます。
問題は、Subversion にチェリー ピッキングを処理させた場合にのみ発生します。トランクからブランチにマージすると、Subversion はブランチにあるトランクのリビジョンを追跡します。しかし、Subversion には、フィーチャー ブランチのどのリビジョンがトランク マージの結果であったかを知る方法がありません。
したがって、機能ブランチをトランクにマージすると、Subversion はマージされていないすべてのリビジョン (トランクからブランチへのマージの結果であるリビジョンを含む) を考慮し、これらすべてのリビジョンをトランクにマージしようとします。
これを処理するために、Subversion には再統合マージと呼ばれる特別なマージがあります。トランクの最後の変更セットをブランチにマージしてから、ブランチをトランクにマージするときに、トランクとブランチを同一にしたいと考えています。したがって、Subversion は双方向のマージを行い、トランクとブランチを一致させたいと考えています。
Subversion の古いバージョンでは、コマンドの--reintegration
パラメーターを使用して、この双方向マージを行うことを手動で指定する必要がありました。svn merge
Subversion のマージ トラッキングは、機能ブランチの再利用に関する興味深い問題にもつながります。トランクからブランチへの最後の一連のマージを行うとしましょう。トランクの最後のリビジョンと Subversion の最後のリビジョンはリビジョン 100 でした。トランクからの変更をブランチにマージすると、ブランチにリビジョン 101 が作成されます。そのブランチのsvn:mergeinfo
プロパティは、トランクのみのブランチからリビジョン 100 までのすべての変更をマージしたことを示しています。
ここで、再統合マージを実行し、変更をコミットして、トランクにリビジョン 102 を作成します。
ここで、トランク (リビジョン 103 としましょう) でさらに作業を行い、それらの変更をフィーチャー ブランチにマージしたいと考えています。
トランクから機能ブランチにマージした最後のリビジョンは何ですか? を見るとsvn:mergeinfo
、リビジョン 100 であることがわかります。トランクからブランチへの前回のマージ以降、トランクには 2 つの新しいリビジョンがあり、まだ機能ブランチにマージされていません: リビジョン 102 とリビジョン 103.
そのため、Subversion は厳選して、リビジョン 102 とリビジョン 103 に含まれる変更をフィーチャー ブランチにマージしようとします。しかし待ってください... リビジョン 102 は、すべての機能ブランチの変更がトランクにマージされていることです! これらの機能の変更を機能ブランチに再適用します!
これを処理するには 2 つの方法があります: 方法 1:再統合マージを実行したら、そのフィーチャー ブランチを二度と使用しないでください。消して。尼僧院に閉じ込めてください。二度とその名を口にするな。そのフィーチャー ブランチがもう一度必要な場合は、トランクから新しいフィーチャー ブランチを作成する必要があります。
もう 1 つの方法はsvn:mergeinfo
、トランクのリビジョン 102 が既に機能ブランチにマージされていることを Subversion に知らせるために、機能ブランチを変更することです。--record-only
次のパラメータを使用してこれを行うことができます。
$ svn co $REPO/branches/feature/myproj
$ cd myproj
$ svn merge --record-only -r102 $REPO/trunk/myproj
おわかりのように、この手動の作業はすべて、そのスイッチをいつ使用するかを知り、再統合--reintegration
マージを行うときに何が起こるかを理解することで、混乱を引き起こしました。したがって、Subversion の新しいバージョン (リビジョン 1.8 以降と思われます) では、これを処理しようとしています。
Subversion 1.8 をクライアントとして使用している場合は、--reintegration
パラメーターを指定する必要はありません。Subversion は、通常の 3 者間マージを実行しているか、再統合マージを実行しているかをプログラムで判断し、それに応じて動作します。
Subversion がreintegration mergeと見なすことをしようとして、すべてのトランク リビジョンをフィーチャー ブランチにまだマージしていない場合、Subversion は警告を発し、マージを許可しません。再統合マージを行った後に機能ブランチを再利用すると、Subversion はこれを検出し、再統合後にブランチの再利用の問題を自動的に処理すると想定されます。(完全に機能しない場合もあります。ただし、Subversion では、再統合マージ後に機能ブランチを再利用することはできませんが、エラーが発生する可能性があり、手動で--record-only
マージを行う必要がある場合があります。)
では、Subversion では、ワークフローをどのように行うべきでしょうか?
各バグと機能を独自のブランチに配置する必要がある Git とは異なり、そのバグ修正または機能を複数のブランチにマージする必要が少なく、ほとんどすべての作業をトランク (または好きなブランチ) からすぐに実行できます。ほとんどの Subversion ショップでは、分岐は候補リリースに対してのみ行われます。つまり、私はリリースをしようとしています。そのリリースのためにブランチします。一部の開発者はリリースに取り組んでおり、他の開発者はトランクの作業を続けています。
トランクでバグが見つかった場合は、トランクで修正でき、そのバグが修正されたリビジョンまたはリビジョンのセットをリリース ブランチにマージできます。または、トランクで修正する必要がある機能ブランチのバグを見つけた場合は、機能ブランチでそのバグを修正し、そのリビジョンまたはリビジョン セットをトランクにマージできます。
シンプルでわかりやすく、実装も簡単です。
これは、機能のために分岐できないという意味ではありません。実際、そうしなければならないこともあります。将来的に実装される機能を想像してみてください。これらの変更をトランクに加えたくありません。その場合、フィーチャー ブランチを作成し、トランクの変更を定期的にそのフィーチャー ブランチにマージします。その機能をトランクにマージするときに問題が発生する可能性があることに注意してください。何が起こっているのかを理解する限り。問題ありません。
また、機能やバグごとに膨大な数のブランチを作成して独り占めしたい場合は、それも可能です。ただし、Subversion 1.8 を使用することをお勧めします。