競合の解消

リポジトリからあなたのファイルを更新・マージしたり、別の URL に作業コピーを切り替えたりすると、時には 競合 することもあります。競合には以下の二種類があります。

ファイル競合

複数の開発者が、同じファイルの同じ行を変更すると、ファイルの競合が発生します。

ツリー競合

開発者がファイルやフォルダの移動・名前変更・削除を行い、別の開発者も移動・名前変更・削除を行ったり、単に変更すると、ツリーの競合が発生します。

ファイル競合

競合は複数の開発者が、あるファイルの同じ行を変更した際に発生します。Subversion はプロジェクトについては何も知りませんから、開発者間の競合については解決できません。競合が報告されたら、問題のファイルを開き、<<<<<<< で始まる行を探してください。競合のある箇所は以下のようにマークがつけられています。

	<<<<<<< filename
		あなたの変更
	=======
		リポジトリからマージされたコード
	>>>>>>> revision
	

また、競合のあるファイルごとに Subversion は手元のディレクトリにファイルを 3 つ追加します。

filename.ext.mine

作業コピーを更新する前に、(競合マーカがついていない) 作業コピーに存在するファイルです。このファイルには最新の変更以外何もありません。

filename.ext.rOLDREV

作業コピーを更新する前の BASE リビジョンのファイルです。最新の編集を行う前、チェックアウトした状態のファイルです。

filename.ext.rNEWREV

作業コピーを更新したときに Subversion クライアントが受信したファイルです。リポジトリの最新 (HEAD) リビジョンに相当します。

外部マージツール・競合エディタを TortoiseSVN競合の編集 で起動できますし、競合の解消に他のエディタを使って手で修正もできます。コードがどうあるべきか決めて、必要な変更をしてから保存してください。

その後、TortoiseSVN問題の解消 コマンドを実行し、リポジトリに変更をコミットしてください。問題の解消コマンドは、実際には競合を解消しないことに注意してください。変更をコミットできるよう、filename.ext.mine ファイルや filename.ext.r* ファイルを削除するだけです。

バイナリファイルが競合した場合、Subversion はそのファイルをマージしようとしません。手元のファイルには変更を加えず (あなたが変更したままを保証)、filename.ext.r* ファイルを作ります。自分の変更を破棄し、リポジトリのバージョンにしたい場合は、「元に戻す」コマンドを使うだけです。リポジトリのバージョンを自分の変更したファイルで置き換えるのなら、「問題の解消」コマンドを行ってコミットしてください。

親フォルダを右クリックし、TortoiseSVN問題の解消... を選択すると、「問題の解消」コマンドを複数のファイルに実行できます。指定したフォルダにある競合したファイルがすべてダイアログに表示されます。解消するものを選択してください。

ツリーの競合

開発者がファイルやフォルダを移動・名前変更・削除したときに、別の開発者が移動・名前変更・削除を行っていたり、変更をしていたりすると、ツリーの競合が発生します。ツリーの競合はさまざまな状況で起こり得ますし、その競合を解消するにはそれぞれ異なった手順が必要です。

また、ファイルが Subversion によりローカルで削除されると、ローカルファイルシステムからも削除されるため、ツリーの競合があったとしても競合のオーバーレイを表示できず、競合を解消しようと右クリックもできません。競合の編集 オプションを用いる代わりに、変更をチェック ダイアログを使用してください。

TortoiseSVN は 変更をマージするための正しい場所を見つけるのを支援しますが、競合を整理するにはさらに作業が必要かもしれません。作業中の BASE を更新すると、常に更新時のリポジトリにある各項目のリビジョンが含まれます。更新後に変更を取り消した場合、そのリポジトリの状態へと戻り、変更開始時の状態には戻りません。

ローカルで削除、更新により編集を受信

  1. 開発者 A がFoo.c を変更し、リポジトリにコミットします。

  2. 開発者 B は、同時に作業コピーで Foo.cBar.c に移動したり、単にその親フォルダで Foo.c を削除しました。

開発者 B の作業コピーを更新した結果、以下のようにツリーの競合が発生します。

  • Foo.c が作業コピーからすでに削除されていますが、ツリーの競合としてマークされます。

  • 削除ではなく名前変更の結果の競合の場合、Bar.c は追加としてマークされますが、開発者 A の変更点は含まれていません。

開発者 B は、現在、開発者 A の変更を保持するかどうかを選ばなければなりません。ファイルの名前変更の場合では、名前変更されたファイル Bar.c に、Foo.c に行った変更をマージできます。シンプルなファイルやディレクトリの削除の場合には、開発者 A の変更を保持し削除を取り消すという選択もできます。もしくは、何もせずに競合解決マークをつけ、事実上開発者 A の変更を破棄します。

名前変更された Bar.c のオリジナルファイルが見つかれば、競合編集ダイアログは変更をマージするか訊いてきます。どこで更新を実行したかによって、ソースファイルが見つからない可能性があります。

ローカルで編集、更新により削除を受信

  1. 開発者 A が Foo.cBar.c に移動し、リポジトリにコミットします。

  2. 開発者 B は Foo.c を、自分の作業コピーで変更します。

またはフォルダ移動の場合...

  1. 開発者 A は、親フォルダ FooFolderBarFolder に移動し、リポジトリへコミットします。

  2. 開発者 B は Foo.c を、自分の作業コピーで変更します。

開発者 B の作業コピーを更新した結果、ツリーが競合しました。単純なファイルの競合では以下のようになります。

  • Bar.c へ作業コピーへ通常ファイルとして追加されます。

  • Foo.c は (履歴と共に) 追加されたとマークされ、ツリーの競合があります。

フォルダの競合では以下のようになります。

  • BarFolder が作業コピーに、通常のフォルダとして追加されます。

  • FooFolder (履歴と共に) 追加されたとマークされ、ツリーの競合があります。

    Foo.c は変更されたとマークされます。

開発者 B は今回、開発者 A の再編成を受け入れ、新しい構造にある対応するファイルに変更をマージするか、開発者 A の変更を取り消し、自分のファイルを保持するかを決めねばなりません。

自分の変更を入れ替えてマージするため、開発者 B はまず、競合ファイル Foo.c がリポジトリ中で名前変更・削除されたファイル名を探さなければなりません。ログダイアログを使用するとわかります。その後、その変更を手でマージしなければなりません。現在のところ、この手順を自動化する方法はなく、単純にする方法すらないからです。一旦変更を移植してしまえば、競合したパスは余分なものとなり、削除できます。この場合、競合エディタダイアログの 削除 ボタンを使用し、掃除と競合解決マークを付けてください。

開発者 A の変更は誤りだと開発者 B が判断した場合、競合エディタダイアログの 保持 ボタンを選択しなければなりません。これは 競合したファイルやフォルダを、解決としてマークますが、開発者 A の変更は手で削除する必要があります。何が移動されたかを見つけ出すには、またログダイアログが役に立ちます。

ローカルで削除、更新により削除を受信

  1. 開発者 A が Foo.cBar.c に移動し、リポジトリにコミットします。

  2. 開発者 B が Foo.cBix.c に移動します。

開発者 B の作業コピーを更新した結果、以下のようにツリーの競合が発生します。

  • Bix.c は、履歴と共に、追加されたとマークされます。

  • Bar.c は、作業コピーへ「通常」状態で追加されます。

  • Foo.c は削除マークが付き、ツリーが競合した状態となります。

競合を解決するには、Foo.c がリポジトリで名前変更・移動したことに対する競合したファイルの名前を、開発者 B が調べなければなりません。ログダイアログで行えます。

開発者 B が、Foo.c の新しい名前の方を残すと決めた場合、開発者 A にしてもらうか、自分で名前変更できます。

開発者 B が、手で競合を解決した後で、競合エディタダイアログのボタンで、ツリーの競合に解決マークを付ける必要があります。

ローカルで紛失、マージにより編集を受信

  1. トランクで作業している開発者 A が、Foo.c を変更しリポジトリにコミットします。

  2. ブランチで作業している開発者 B が、Foo.cBar.c に移動し、リポジトリにコミットします。

開発者 A のトランクへの変更を、開発者 B のブランチにマージすると、作業コピーが以下のようにツリーの競合状態になります。

  • Bar.c は、状態が「通常」で、すでに作業コピーにあります。

  • Foo.c はツリーの競合として、紛失マークが付きます。

この競合を解決するには、開発者 B が競合エディタダイアログでファイルに解決マークを付け、競合リストから取り除く必要があります。さらに、紛失ファイル Foo.c を、リポジトリから作業コピーへコピーするか、Foo.c へ行った開発者 A の変更を、名前変更した Bar.c にマージするか、競合に解決マークを付ける他は何もしないかを決めなければなりません。

紛失したファイルをリポジトリから取得し、それから解決マークを付けると、あなたのコピーが再度削除されます。まず競合を解決しなければなりません。

ローカルで編集、マージにより削除を受信

  1. トランクで作業している開発者 A が、Foo.cBar.c に移動し、リポジトリにコミットします。

  2. ブランチで作業している開発者 B が、Foo.c を変更しリポジトリにコミットします。

フォルダの移動と同等ですが、Subversion 1.6 でもまだ検出できません……

  1. トランクで作業している開発者 A が、親フォルダ FooFolderBarFolder に移動し、リポジトリにコミットします。

  2. ブランチで作業している開発者 B が、自分の作業コピーにある Foo.c を変更します。

開発者 A のトランクへの変更を、開発者 B のブランチにマージすると、作業コピーが以下のようにツリーの競合状態になります。

  • Bar.c には追加マークが付きます。

  • Foo.c はツリーの競合として、変更マークが付きます。

開発者 B は今回、開発者 A の再編成を受け入れ、新しい構造にある対応するファイルに変更をマージするか、開発者 A の変更を取り消し、自分のファイルを保持するかを決めねばなりません。

自分の手元の変更をバラバラにしてマージするために、開発者 B は、競合ファイル Foo.c がリポジトリで、どのファイル名に名前変更・移動されたかを、まず調べなければなりません。マージソースのログダイアログを使用して行うことができます。競合エディタは、マージで使用されるパスを知らず、作業コピーのログを表示するだけですので、自分で探さなければなりません。そして今回、マージを自動化することも、簡単にマージする方法すらない場合は、変更を手でマージしなければなりません。一度変更を適用してしまえば、競合したパスはもう必要なく、削除できます。この場合、掃除と競合に解決マークをつけるために、競合エディタの 削除 ボタンを使用してください。

開発者 B が、開発者 A の変更は誤りだと判断した場合、競合エディタダイアログの 保持 ボタンを選択しなければなりません。これは 競合したファイルやフォルダを、解決としてマークますが、開発者 A の変更は手で削除する必要があります。何が移動されたかを見つけ出すには、またマージソースのログダイアログが役に立ちます。

ローカルで削除、マージにより削除を受信

  1. トランクで作業している開発者 A が、Foo.cBar.c に移動し、リポジトリにコミットします。

  2. ブランチで作業している開発者 B が、Foo.cBix.c に移動し、リポジトリにコミットします。

開発者 A のトランクへの変更を、開発者 B のブランチにマージすると、作業コピーが以下のようにツリーの競合状態になります。

  • Bix.c は通常 (未変更) 状態としてマークされます。

  • Bar.c は履歴と共に追加マークが付きます。

  • Foo.c には紛失マークが付き、ツリーの競合状態となります。

競合を解決するために、開発者 B は競合ファイル Foo.c がリポジトリ中で名前変更・削除されたファイル名を探さなければなりません。マージソースのログダイアログを使用するとわかります。競合エディタは、マージで使用されるパスを知らず、作業コピーのログを表示するだけですので、自分で探さなければなりません。

開発者 B が、Foo.c の新しい名前の方を残すと決めた場合、開発者 A にしてもらうか、自分で名前変更できます。

開発者 B が、手で競合を解決した後で、競合エディタダイアログのボタンで、ツリーの競合に解決マークを付ける必要があります。