svn:externals が設定されている状況で簡単に branch を切る

svn の branch は svn copy だけで簡単に作成できますが、厄介なのが外部項目の参照(svn:externals)です。
svn 1.4 までは、この外部項目が絶対パスでしか指定できなかったため、

  • branch を切った後は、svn:externals の再設定が必要
  • branch から trunk に merge するときも、 svn:externals の再設定が必要

と手間がかかりました。
svn 1.5 では相対パスの指定が可能になったため、ずっと簡単に branch を作成することができるようになりました。とはいえ、諸諸 trap がありましたので、手順を紹介。


ちなみに私は極力 URL 指定で branch を切ったりせず、ワーキングコピーで作業するようにしています。
URL 指定の結果はサーバ内部だけで処理が進んでしまい、作業の結果で本当に test をパスするかが怪しいと思っているので。また、過去 svnリポジトリ構成が複雑過ぎたため、 URL 指定だと間違いが頻発してしまったというのも理由のひとつです。

事前の準備

branch を切りやすい構成にする。

相対パスで branch を切りやすくするためには、以下のような構成にします。

  • trunk
    • project1
    • project2
    • common
  • branch
  • tags
    • milestone1
      • project1
      • project2
      • common
    • milestone2
      • project1
      • project2
      • common

逆の project1, project2, common を root directory に置く方法は、この場合はとれません。

どちらを採用すべきか?は、

  • project1, project2 がほぼ一体の組の場合は、trunk, branch, tags が root に
  • project1, project2 にあまり関連性がない場合は、 project1, project2 が root に

するべきではないかと思います。

今回の場合は、common/lib を project1 と project2 で共有するため、前者に該当します。

svn:externals を設定する。

project1/lib, project2/lib が common/lib を相対パスで参照する場合、以下のように設定します。

$ cd #{project1 or project2}
$ svn propset svn:externals '../common/lib lib' .

svn 1.4 では、 '../common/lib' と 'lib' の指定順が逆でした。

branch を切る

svn copy で branch を作成

branch は通常の svn copy にて行います。

$ svn copy trunk branches/bug_no514


branch を作成したら、 branch の project1/lib に移動して svn info を確認してみると、
branch の project1/lib は trunk の common を参照しています。

$ svn info branches/bug_no514/project1/lib
パス: branches/bug_no514/project1/lib
URL: https://svn.foo.com/trunk/common/lib          # ← ココ
    :

どうやら svn copy で copy した場合は、 svn:externals の実際の参照先は copy 元と同じ場所のままでコピーしてしまうようです。


しかしながら、 svn propget svn:externals で設定を確認すると、 正しく ../common/lib が参照されています。

$ svn propget svn:externals branches/bug_no514/project1
../common/lib lib


すなわち、設定(属性)と実体(ディレクトリ)が不整合な状態になっています。次でこれを解消します。

一旦 commit する。

次の作業に進むにあたり、一回 commit が必要なので行います。

設定(属性)と実体(ディレクトリ)が不整合を解消する

2 つ対応方法があります。

  1. working copy 上の branch を一旦すべて削除して、再度 checkout する。
  2. 上記以外の方法で対応する。

上記の 1. は簡単なので、 2. の対応方法を紹介します。

以下のように誤った参照を行っているディレクトリを削除し、その後 svn up で復元します。

$ cd branches/bug_no514
$ rm -rf `svn st | egrep '^X' | awk '{print $NF}'`
$ svn up


以上で svn:externals の書換えを行わずに branch の作成が完了します。



trunk へのマージを行う際も svn:externals が破壊されることがないので、
branch/merge が相当手軽に行えるようになります。