ksaitoの日記

日々試したことの覚え書き

マージトラッキング

Subversionは、バージョン1.5からマージトラッキングという仕組みが実装されています。
ブランチの運用として機能ブランチを使っている場合にとても便利なのですが、具体的な例がないと、なかなか「これは、便利!」と実感がわきません。
マージトラッキングの機能を簡単なサンプルで使ってみました。
もう、以前の方法は必要ありません!

前提と想定

そもそも機能ブランチを作らなくてよければ、それにこしたことはありません。
また、必要に迫られて作成する場合は、trunkに戻す段取りを良く話し合っておく必要があります。

例えば、小規模で重要な新機能の開発とOSやミドルウェア、開発言語のバージョンアップによるより広範囲で時間のかかるメンテナンスが同時期に必要なケースを想定します。
新機能の開発は、保守の内容を含まずに最短でリリースする必要があり、保守は新機能を含む全ての機能について十分なテストをした後でリリースする必要があります。

また、マージトラッキングが実装されたのは、Subversionの(多分)1.5からです。
それ以前のバージョンで作成したリポジトリでは機能しません。
Subversion 1.5以上でリポジトリを作ってダンプ&ロードで引っ越しするしかないです。

テスト用のリポジトリ構成

trunkのソースから同時期に新機能開発の機能ブランチと保守のための機能ブランチを作成します。
次のようにnewfuncが新機能開発用、mainteが保守用の機能ブランチとします。

$ svn ls $REPO
branches/
tags/
trunk/
$ svn ls $REPO/trunk
file.txt
$ svn copy $REPO/trunk $REPO/branches/newfunc -m ""

リビジョン 2 をコミットしました。
$ svn copy $REPO/trunk $REPO/branches/mainte -m ""

リビジョン 3 をコミットしました。
$ 

平行して修正

新機能開発と保守でfile.txtに、それぞれ修正をします。

$ svn co $REPO/branches/newfunc
$ cd newfunc/ 
$ vi file.txt
$ svn diff
Index: file.txt
===================================================================
--- file.txt	(リビジョン 3)
+++ file.txt	(作業コピー)
@@ -1 +1,2 @@
 init
+newfunction
$ svn commit -m ""
$ cd ..
$ svn co $REPO/branches/mainte
$ cd mainte/
$ vi file.txt
$ svn diff
Index: file.txt
===================================================================
--- file.txt	(リビジョン 3)
+++ file.txt	(作業コピー)
@@ -1 +1,2 @@
+maintenance
 init
$ svn commit -m ""
$ 

新機能の開発完了

新機能の開発が完了するとtrunkへマージをします。
以前は、マージするリビジョンを手動で指定していて、リビジョンを間違えると同じ修正が二度マージされたり、マージされないリビジョンがあったりと混乱することがありました。
マージトラッキングはブランチを作成したリビジョンを判別してくれるのでマージしたい対象を指定するだけです。
繰り返しマージしても、マージ済みの修正を適用してしまうことはありません。

$ svn co $REPO/trunk
$ cd trunk
$ svn merge $REPO/branches/newfunc
--- r2 から r4 までを '.' にマージしています:
U    file.txt
$ svn diff

属性に変更があったパス: .
___________________________________________________________________
追加: svn:mergeinfo
   /branches/newfunc:r2-4 をマージしました

Index: file.txt
===================================================================
--- file.txt	(リビジョン 3)
+++ file.txt	(作業コピー)
@@ -1 +1,2 @@
 init
+newfunction
$

ここでもう一度、マージしても繰り返しマージすることはありません。

$ svn merge $REPO/branches/newfunc
$

マージ後に修正があった場合でも同じ操作で前回マージからの修正が適用されます。

$ cd ../newfunc/
$ echo newfunction2 >> file.txt 
$ svn commit -m ""
$ cd ../trunk
$ svn merge $REPO/branches/newfunc
--- r9 を '.' にマージしています:
G    file.txt
$ svn diff

属性に変更があったパス: .
___________________________________________________________________
追加: svn:mergeinfo
   /branches/newfunc:r3-9 をマージしました

Index: file.txt
===================================================================
--- file.txt	(リビジョン 7)
+++ file.txt	(作業コピー)
@@ -1 +1,3 @@
 init
+newfunction
+newfunction2
$ svn commit -m ""
$ 

メンテナンスの完了

メンテナンスが完了したら、こちらも同じ手順でマージします。

$ svn merge $REPO/branches/mainte
--- r4 から r11 までを '.' にマージしています:
U    file.txt
$ svn diff

属性に変更があったパス: .
___________________________________________________________________
追加: svn:mergeinfo
   /branches/mainte:r4-11 をマージしました
   /branches/newfunc:r3-9 をマージしました

Index: file.txt
===================================================================
--- file.txt	(リビジョン 4)
+++ file.txt	(作業コピー)
@@ -1 +1,4 @@
+maintenance
 init
+newfunction
+newfunction2
$

いずれにしても、ブランチとtrunkが長期間分離しないように運用するのが肝要です。