* Subversionにおけるブランチ [#g6c33a4e] #contents ** Subversionにおけるブランチの概念 [#z99c7e96] Subversionにおけるブランチの概念は、単なるフォルダやファイルのコピーです。 例えば、trunkフォルダで作業中に、試験的にXという機能を実装する必要が出たとします。Xは、実際に使われるかどうかまだわかりません。 もしtrunkフォルダ上のファイルにXに関する変更を加えると、Xが正しく動くまでテストなどが出来ない状態になり、Xはいらないよ、ということになった時に、元に戻すのが大変です。 そこで、branch-xという名前でtrunkフォルダのコピーをつくり、そこで作業すれば、trunkフォルダの中身に影響を与えずに済みます。 trunkはtrunkで改良などが続き、branch-xではXの機能実装が行われる訳です。その間、trunkとbranch-xは、互いに影響を与えることはありません。 Xの機能はいらないとわかったら、branch-xフォルダを削除すれば良いですし、まぁ後々役に立つかもしれないと思うなら、残しておいても良いでしょう。trunkには影響を与えないので、残しておいても害はありません。 もしXの機能が必要なのでtrunkに組み込む、ということになれば、brach-xを、trunkに「マージ」することで、trunkにbranch-xの変更を適用できます。 これで、面倒な依存影響に煩わされることなく、開発を行うことが出来ます。 ** 前提 [#hba18d51] まず、trunkのみで、リビジョン120まで開発したとします。 そこで、機能Xの実装を試みるために、trunkをbranch-xという名前でコピーします。ここで、リビジョンは121になります。branch-xは、リビジョン121で作成されます。 そして、trunkとbranch-xの両方の更新が行われ、レポジトリのリビジョンは150まで上がったとします。そこで、機能Xをtrunkに取り込むことにします。 ちなみに、レポジトリ構造としては、 http://server/svn/project1/ - レポジトリのルートフォルダ http://server/svn/project1/trunk - 主開発フォルダ http://server/svn/project1/tags - タグ用のフォルダ http://server/svn/project1/branches - ブランチ用フォルダ http://server/svn/project1/branches/branch-x - Xの機能をためしに実装してみるフォルダで、 リビジョン120のhttp://server/svn/project1/trunkをコピーして作られた という感じになります。 ** 操作の流れ [#n779afa9] 最初に、操作の流れだけ書いておきます。まとめや結論を先に、です。 + ブランチを作る(trunkを、branch-xとしてコピーする) + trunkとbranch-xでそれぞれ開発を行い、必要に応じてtrunkの修正をbranch-xに取り込む(マージする) + trunkにXの機能追加を適用するために、branch-xの修正をtrunkに取り込む(マージする) 2.のマージ作業をこまめにやっておくと、3.のマージ作業が楽になります。 ** ブランチの作り方 [#f2c7d4f1] 単純にコピーを行うだけです。基本はフォルダ単位で行います。 コマンドラインなら、svn copyコマンドを使って、trunkフォルダをbranch-xというフォルダでコピーしてください。 TortoiseSVNであれば、http://tortoisesvn.bluegate.org/Help/dailyuseguide.html#Copy辺りを参考にしてください。このページで、to URLにbranch-xという名前(正確には、フルURLにする必要があるが)を指定すれば、ブランチの作成が可能です。 Subclipseなら、プロジェクトリストのフォルダを右クリックして、Teamの所からブランチを作成できます。 ブランチは、レポジトリ内のコピーなので、作った直後は(ローカル側では)何も起きません。 なお、レポジトリ内では、リンクによりコピーが行われるので、巨大なファイルだろうが何だろうが気にする必要はありません。 ** ブランチの使い方 [#o196fd84] ブランチの使い方は二通りあります。 一つは、レポジトリ切り替えを行って、trunkの編集をやめてbranch-xの編集を始める方法です。 もう一つは、branch-xを新しくチェックアウトする方法です。 ここでは、後者をお奨めするので、その方法についてです。 trunkをチェックアウトした時と同じように、branch-xを指定してチェックアウトしてください。 操作はそれだけです。ローカル作業領域には、trunkとbranch-xの二つができることになります。 これで、同時に、もともとのtrunkの開発も行えて、branch-xでXの機能追加も行えます。 ** trunkの修正をbranch-xに反映させる [#e5b66d31] trunkで重要なバグ修正等があると、branch-xも更新する必要が出てきます。そうしないと、バグのあるままXの機能実装をすることになりますから。 そこで、trunkの修正をbranch-xに反映させる必要が出てきます。 マージ作業の原理は、次のようになります。 *** マージの原理 [#y8836596] まず、trunkのリビジョンを二つ指定します。その二つのリビジョンの期間にtrunkに行われた変更点を、branch-xのローカルコピーに適用します。 リビジョンを含めて説明すると、リビジョン120からリビジョン150までの間に、trunkに行われた変更を、branch-xに適用すれば、branch-xの元となったtrunkは見かけ上、リビジョン120のものからリビジョン150のものになります。これがマージです。 マージは行単位で行われます。いわゆるdiffと同じ原理です。もし行単位でマージが出来ない場合は、手作業でのマージとなります。 自動マージは行単位で行われます。いわゆるdiffと同じ原理です。もし行単位でマージが出来ない場合は、手作業でのマージとなります。 マージできる例としては、次のようなものがあります。 自動マージできる例としては、次のようなものがあります。 trunk@120 if(a > b) { x++; } trunk@150 if(a > b) { y--; x++; } branch-x@150 if(a > b) { x++; z = 0; } branch-x@マージ結果 if(a > b) { //この行は両方一致 y--; //trunk@150からもってきて追加した x++; //この行は両方一致 z = 0; //branch-xからもってきて追加した } //この行は両方一致 マージできない例としては、次のようなものがあります。 自動マージできない例としては、次のようなものがあります。 trunk@120 if(a > b) { x++; } trunk@150 if((a > b) && (c < 0)) { y--; x++; } branch-x@150 if((a > b) && (c < b)) { x++; z = 0; } branch-x@マージ結果 if((a > b) && (c < 0) && (c < b)) { //手作業でマージする必要がある y--; //trunk@150からもってきて追加した x++; //この行は両方一致 z = 0; //branch-xからもってきて追加した } //この行は両方一致 このように、trunkかbranch-xのどっちかの行を組み合わせてマージできない場合は、手作業でマージする必要が出てきます。もちろん、それ以外の場所は極力自動でマージされます。 *** 操作方法 [#s2184d89] コマンドラインの場合は、svn mergeコマンドを使ってください。 svn merge -r [旧リビジョン]:[新リビジョン] [trunk(URL)] [branch-x(パス)] です。変更元のtrunkの指定はレポジトリのURLであるのに対し、適用先のbranch-xの指定はローカル作業域へのパスであることに注意してください。 TortoisSVNなら、branch-xフォルダに対して、マージを実行してください。http://tortoisesvn.bluegate.org/Help/dailyuseguide.html#Mergeに、trunkへのマージの仕方がありますので、違いに気をつけながら(今は、branch-xへのマージです)参考にしてください。 Subclipseなら、プロジェクトリストのbranch-xフォルダを右クリックして、Teamからマージを選び、マージ元にtrunkのURLを指定して、リビジョン番号を指定しましょう。 この作業により、ローカルにあるbranch-xの作業領域が更新されます。branch-xをコミットすれば、レポジトリにも反映されます。 ** branch-xの機能をtrunkに反映させる [#oe371026] 基本は前述のマージ手順と同じで、対象が逆転しただけです。つまり、今までの説明だと、trunkの変更 =>> branch-x、だったのが、branch-xの変更 =>> trunk、になっただけです。 注意すべき点だけを書いておきます。 - マージの適用先は、ローカルにあるtrunk - マージの適用元は、レポジトリにあるbranch-x - マージの開始リビジョンは、branch-xをコピーした時(ブランチを作った時=リビジョン121) - マージの終了リビジョンは、branch-xを最後に更新したりビジョン(HEADリビジョンでも別に構わない) ということです。 ** 終わりに [#n9a9f5b5] trunkとbranch-xをそれぞれチェックアウトしたのは、両方の作業を簡単に進められるというだけではなく、trunkの変更を簡単に知ることが出来るように、という意味もあります。 trunkが変更されたことがわかったら、コミットコメントを見て、必要な部分をbranch-xに適用しましょう。バグのあるままbranch-xの開発をしても苦労するだけでしょう。多分。 こまめにマージしてtrunkの変更を取り込んでおけば、最後にtrunkにマージする時に一度にマージ作業をやる手間が省けます。