SVN ブランチ作成からマージまでの手順を分かりやすく紹介

はい、承知いたしました。Subversion (SVN) におけるブランチ作成からマージまでの手順について、詳細かつ分かりやすい説明を含む記事を作成します。約5000語を目指し、各ステップの背景、コマンド、注意点、トラブルシューティングなどを網羅的に解説します。


SVN ブランチ作成からマージまでの手順を徹底解説:並行開発とリリース管理のための実践ガイド

はじめに:SVNにおけるブランチとマージの重要性

ソフトウェア開発において、複数の機能開発を並行して進めたり、特定のリリースバージョンを管理したり、本番環境に影響を与えずにバグ修正を行ったりする必要は頻繁に発生します。このような要求に応えるために不可欠なのが、「バージョン管理システム」における「ブランチ(Branch)」と「マージ(Merge)」の概念です。

Subversion (SVN) も例外ではなく、ブランチとマージの機能を強力にサポートしています。正しくブランチとマージを使いこなすことは、チーム開発の効率を向上させ、開発プロジェクトをスムーズに進行させる上で極めて重要です。しかし、SVNのブランチとマージは、特に初心者にとっては理解が難しく、マージの際にコンフリクト(競合)が発生したり、意図しない結果になったりすることも少なくありません。

本記事では、SVNにおけるブランチの作成から、そのブランチでの作業、そして最終的に元のライン(通常はトランク)へマージするまでの全過程を、初心者の方でも分かりやすいように詳細かつ具体的に解説します。各ステップで実行するコマンド、そのコマンドが何をしているのか、なぜそのステップが必要なのか、そして注意すべき点やトラブルシューティングについても触れていきます。

この記事を読むことで、あなたはSVNのブランチとマージの基本から応用までを理解し、自信を持って日々の開発業務に活用できるようになるでしょう。

前提知識と準備

本記事を読むにあたり、以下の前提知識があるとより理解が進みます。

  • Subversion (SVN) の基本的な概念:リポジトリ、リビジョン、ワーキングコピー、コミット、アップデートなど。
  • コマンドライン(CUI)の操作:cd, ls (または dir) などの基本的なファイル・ディレクトリ操作。
  • テキストエディタの操作:コードや設定ファイルを編集できること。
  • コンフリクト解決のためのツール(任意):マージツールやエディタでの手動解決方法を知っていること。

また、実際に手を動かして試す場合は、以下の準備が必要です。

  • SVN クライアント:コマンドラインクライアント (svn) または GUI クライアント(TortoiseSVN, RapidSVN など)。本記事ではコマンドラインクライアントを中心に解説します。
  • SVN リポジトリへのアクセス権限:ブランチを作成し、コミットできる権限が必要です。
  • 作業用のワーキングコピー。

SVNリポジトリの標準的な構造 (/trunk, /branches, /tags)

SVNにおいて、ブランチとマージを効果的に行うためには、リポジトリのディレクトリ構造を標準的なものにしておくことが強く推奨されます。これはSVNのツールやコマンドが、この構造を前提としている部分があるためです。標準的な構造は以下のようになります。

/
|-- trunk/ (メインの開発ライン)
|-- branches/ (各開発ブランチを格納するディレクトリ)
| |-- feature_x/
| |-- bugfix_y/
| |-- release_1.0/
| `-- ...
|-- tags/ (特定の重要な時点のスナップショットを格納するディレクトリ)
| |-- v1.0.0/
| |-- v1.1.0_release/
| `-- ...

  • /trunk:
    • 「トランク」または「幹線」と呼ばれ、プロジェクトの主要な開発ラインです。通常、最新の安定版または開発中の最新版が置かれます。
    • 日常的な開発作業は、この/trunkに対して行われることが多いです。
  • /branches:
    • /trunkから派生した、並行開発用のブランチを格納するためのディレクトリです。
    • 新機能の開発、バグ修正、特定のバージョンの準備など、メインラインから一時的に分離して作業を行う場合に使用します。
    • 各ブランチは通常、その目的(例: feature_login, bugfix_issue123)や関連するバージョン名(例: release_2.0)をディレクトリ名として持ちます。
  • /tags:
    • 特定の時点でのリポジトリの状態を記録するためのディレクトリです。主にリリースバージョンや重要なマイルストーンに対して使用されます。
    • タグは開発を行うためのものではありません。タグはあくまで過去の特定のリビジョンを参照するための「スナップショット」として扱われます。一度作成されたタグの内容は変更しないことが前提です。SVNではブランチとタグは技術的には同じ svn copy で作成されますが、運用上の目的が異なります。

この標準構造に従っておくことで、後述するブランチ操作やマージ操作が直感的になり、svn merge コマンドの -c (チェンジセット) や --reintegrate などのオプションも正しく機能しやすくなります(特に古いSVNバージョンや特定のマージ戦略の場合)。

本記事では、この標準的なリポジトリ構造を前提として説明を進めます。

ステップ1:ブランチを作成する目的を理解する

ブランチを作成する前に、なぜブランチが必要なのか、その目的を明確にすることが重要です。主な目的は以下の通りです。

  • 新機能開発 (Feature Branching):
    • 大規模な新機能や実験的な機能の開発を、メインの開発ラインである/trunkから分離して行いたい場合。
    • 開発中の機能が不安定でも、/trunkの安定性を保つことができます。
    • 開発が完了し、十分にテストされたら、/trunkにマージします。
  • バグ修正 (Hotfix Branching):
    • リリース済みのバージョンや本番環境で発見された緊急度の高いバグを、現在の/trunkでの開発を中断せずに修正したい場合。
    • リリースされたタグや、そのリリースに対応するリリースブランチからブランチを切ります。
    • 修正が完了したら、そのバグ修正が必要なリリースブランチや/trunkにマージします。
  • リリース準備 (Release Branching):
    • 特定のバージョン(例: v1.0)をリリースするための最終準備(バグ修正、ドキュメント更新、最終テストなど)を、次のバージョン(例: v1.1)の開発と並行して行いたい場合。
    • リリースする時点の/trunkからブランチを切ります。
    • ブランチ上での修正は、必要に応じて/trunkにもマージバック(または cherry-pick)します。
    • ブランチが安定したら、そのブランチを元にタグを作成し、リリースします。

目的を理解することで、どのパス(/trunk, /branches/既存ブランチ, /tags/既存タグ)からブランチを作成すべきか、また最終的にどこへマージすべきかが明確になります。

ステップ2:ブランチの作成元を選択する

ブランチを作成する目的が決まったら、次に「どこから」ブランチを作成するかを選択します。これは通常、以下のいずれかです。

  • /trunkから作成:
    • 新しい機能開発や、今後の標準的な開発ラインからの派生ブランチを作成する場合の最も一般的なパターンです。
    • /trunkの最新リビジョン、または特定の安定したリビジョンを指定して作成します。
  • 既存の/branches/以下のブランチから作成:
    • 特定のフィーチャーブランチからさらに派生して、その機能の一部分を独立して開発したい場合など。
  • 既存の/tags/以下のタグから作成:
    • 過去にリリースしたバージョンのタグから、緊急のバグ修正を行うためのホットフィックスブランチを作成する場合など。

通常は/trunkから作成することが多いため、本記事では/trunkからブランチを作成する例を中心に説明します。

ステップ3:ブランチを作成する (svn copy)

SVNにおいてブランチやタグを作成する操作は、svn copy コマンドを使用します。これは一見「コピー」という名前なので、ファイルやディレクトリを物理的にコピーしているように見えますが、SVNリポジトリ内部では非常に効率的な操作として実装されています。

SVNはリビジョン間の差分を管理しており、svn copy は指定されたパスとリビジョンの状態を指す新しいエントリをリポジトリのツリーに追加するだけです。元のデータ自体をコピーするわけではないため、非常に高速で、ディスク容量もほとんど消費しません。この特性により、SVNでは気軽にブランチを作成することができます。

コマンドの基本形式:

bash
svn copy SOURCE_URL DESTINATION_URL -m "コミットメッセージ"

または、ワーキングコピー内のパスを指定してリポジトリへコピー(ローカルからリモートへ)することも可能ですが、通常はURL to URLのコピーが推奨されます。これは、ローカルのワーキングコピーの状態に依存せず、リポジトリの特定のリビジョンを正確にコピーできるためです。

/trunk のHEADリビジョンから新しいフィーチャーブランチを作成する例:

あなたが https://your-svn-repo.com/project というリポジトリを持っており、そこに標準構造 /trunk, /branches, /tags があると仮定します。新しいログイン機能開発用のブランチ feature_login を作成する場合。

“`bash

コマンド実行

$ svn copy https://your-svn-repo.com/project/trunk \
https://your-svn-repo.com/project/branches/feature_login \
-m “Create branch for login feature development”

成功した場合の出力例

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

“`

解説:

  • https://your-svn-repo.com/project/trunk: コピー元(ソース)のURLです。/trunkHEADリビジョン(最新の状態)がデフォルトでコピーされます。
  • https://your-svn-repo.com/project/branches/feature_login: コピー先(デスティネーション)のURLです。/branches ディレクトリの下に feature_login という新しいディレクトリとしてブランチが作成されます。
  • -m "...": このコピー操作自体もSVNリポジトリに対する変更(コミット)として記録されるため、コミットメッセージが必須です。ブランチの目的などを記述します。

特定のリビジョンからブランチを作成する場合:

/trunkの最新ではなく、特定のリビジョン(例: リビジョン 1234)の状態からブランチを作成したい場合は、コピー元のURLに @リビジョン番号 を付けます。

bash
$ svn copy https://your-svn-repo.com/project/trunk@1234 \
https://your-svn-repo.com/project/branches/feature_login_from_r1234 \
-m "Create feature_login branch from trunk@r1234"

確認:

ブランチが正常に作成されたか確認するには、リポジトリブラウザで確認するか、svn list コマンドを使用します。

bash
$ svn list https://your-svn-repo.com/project/branches

出力に feature_login/ が表示されれば成功です。

注意点:

  • -m オプションでコミットメッセージを忘れないようにしましょう。
  • コピー元のURLとコピー先のURLを間違えないように注意しましょう。特にコピー先は/branches/以下に適切な名前で作成してください。
  • svn copy はリポジトリへのコミット操作なので、ネットワーク経由で実行されます。

これで、リポジトリ上に新しいブランチが作成されました。ただし、あなたのローカルのワーキングコピーはまだ/trunk(または以前作業していたブランチ)を指したままです。

ステップ4:作成したブランチへ切り替える (svn switch)

リポジトリに新しいブランチを作成しただけでは、ローカルでの開発作業は始まりません。次に、あなたのワーキングコピーを、今作成したブランチを指すように切り替える必要があります。この操作にはsvn switch コマンドを使用します。

svn switch は、既存のワーキングコピーの内容を、指定したリポジトリのURL(ブランチ、タグ、またはトランク)の内容と同期させるコマンドです。svn checkout と似ていますが、checkout が新しいディレクトリにリポジトリの特定パス全体を取得するのに対し、switch既存のワーキングコピーを効率的に別のパスに切り替える点が異なります。SVNは差分を取得してワーキングコピーを更新するため、checkout よりも高速な場合が多いです。

コマンドの基本形式:

bash
svn switch TARGET_URL [PATH_TO_WORKING_COPY]

通常は、ワーキングコピーのルートディレクトリでコマンドを実行するため、[PATH_TO_WORKING_COPY] は省略可能です。

新しいフィーチャーブランチ feature_login へ切り替える例:

あなたのワーキングコピーが /path/to/your/working_copy にあり、これが現在 /trunk を指しているとします。

“`bash

ワーキングコピーのルートディレクトリに移動

$ cd /path/to/your/working_copy

switch コマンドを実行

$ svn switch https://your-svn-repo.com/project/branches/feature_login

成功した場合の出力例

At revision XXX. (ワーキングコピーが指定されたブランチの最新リビジョンに更新されたことを示す)

“`

解説:

  • https://your-svn-repo.com/project/branches/feature_login: 切り替えたいブランチのURLです。
  • コマンド実行後、ワーキングコピーの内容がリモートの feature_login ブランチの最新状態に更新されます。/trunk には存在しなかったファイルやディレクトリが追加されたり、/trunk とは異なる内容になっているファイルが更新されたりします。

確認:

ワーキングコピーがどのURLを指しているかを確認するには、svn info コマンドを使用します。

bash
$ svn info

出力される情報の中に URL: の項目があり、これが https://your-svn-repo.com/project/branches/feature_login となっていれば成功です。

注意点:

  • switch コマンドを実行する前に、ワーキングコピーに未コミットの変更がない状態にしておくことが推奨されます。未コミットの変更がある場合、SVNは可能な限りその変更を切り替え先のブランチに引き継ごうとしますが、コンフリクトが発生したり、予期せぬ状態になったりする可能性があります。もし未コミットの変更がある場合は、一度コミットするか、svn stash のような機能(SVNには直接的な機能はありませんが、一時的に変更を待避させる手段を検討)を利用するか、変更を元に戻す (svn revert) などを検討してください。
  • switch はネットワーク操作です。
  • switch の代わりにブランチを checkout する方法もあります (svn checkout https://your-svn-repo.com/project/branches/feature_login /path/to/new_working_copy)。これは全く新しい作業ディレクトリを作成する場合に使います。既存の作業ディレクトリでブランチを切り替えたい場合は switch が適切です。

これで、あなたのワーキングコピーは新しく作成した feature_login ブランチを指すようになりました。いよいよこのブランチ上で開発を開始できます。

ステップ5:ブランチ上での開発作業 (svn update, svn add, svn commit など)

ブランチに切り替えたら、通常通りSVNを使った開発作業を行います。このブランチでの作業は、他のブランチ(/trunkを含む)には影響を与えません。

  1. 最新状態への更新:
    作業を開始する前に、ブランチの最新状態にワーキングコピーを更新します。
    bash
    $ svn update

    特にチームで同じブランチを開発している場合は、定期的な update が重要です。

  2. ファイル・ディレクトリの編集:
    必要な機能開発やバグ修正のために、コードやドキュメントを編集します。通常のファイル操作(作成、編集、削除、移動など)を行います。

  3. 変更のSVNへの登録:
    新しくファイルやディレクトリを作成した場合は、SVNに管理対象として登録する必要があります。
    bash
    $ svn add path/to/new/file_or_directory

    ファイルを削除、移動、コピーした場合は、SVNのコマンドを使用します。
    bash
    $ svn delete path/to/file_or_directory
    $ svn move path/to/source path/to/destination
    $ svn copy path/to/source path/to/destination # ワーキングコピー内でのコピー

  4. 変更状態の確認:
    現在のワーキングコピーの変更状態を確認します。
    bash
    $ svn status

    A (Add), D (Delete), M (Modify), ? (Unknown), ! (Missing), C (Conflicted) などの記号で状態が表示されます。

  5. 変更のコミット:
    一連の作業が一段落したら、変更をリポジトリのブランチにコミットします。
    bash
    $ svn commit -m "開発内容を説明するコミットメッセージ"

    コミットメッセージは、何を変更したのか、なぜ変更したのかが分かるように具体的に記述しましょう。これは後々、マージや履歴追跡を行う際に非常に重要になります。

注意点:

  • 必ずブランチ上で作業していることを確認する: svn info コマンドなどで現在のURLが目的のブランチであることを常に意識しましょう。誤って/trunkで作業を進めてしまうと、後でブランチに反映させたり、ブランチでの作業を無駄にしてしまったりする可能性があります。
  • こまめにコミットする: 小さな単位で頻繁にコミットすることで、変更履歴が追いやすくなり、問題が発生した場合に特定の変更を取り消したり(リバート)、原因を特定したりしやすくなります。また、後述のマージ作業におけるコンフリクト発生リスクを軽減することにも繋がります。
  • 他のブランチの変更は反映されない: あなたがブランチ上で作業している間、他の開発者が/trunkや他のブランチにコミットした変更は自動的にはあなたのワーキングコピーに反映されません。必要に応じて後述の「マージバック(他のブランチの変更を取り込む)」操作を行う必要があります。

このステップでは、目的とする機能開発やバグ修正をブランチ上で行います。単独で作業することもあれば、チームメンバーと協力して同じブランチを開発することもあります。

ステップ6:ブランチを最新のトランクの変更で更新する(任意だが推奨)

あなたがブランチ上で開発を進めている間も、他の開発者は/trunkで作業を続けている可能性があります。/trunkに新しい機能が追加されたり、共通部分のバグが修正されたりすることがあります。

あなたがブランチでの開発を完了し、最終的にこのブランチを/trunkにマージしようとした際に、/trunkとあなたのブランチの間に大きな差分があると、マージの際に大規模なコンフリクトが発生する可能性が高まります。

これを避けるために、定期的に(またはマージ前に一度)、/trunkの最新の変更をあなたのブランチにマージすることが推奨されます。この操作は「マージバック」と呼ばれることもありますが、ここでは「他のブランチ(/trunk)の変更をカレントブランチに取り込む」と表現します。

手順:

  1. 作業中のブランチのワーキングコピーにいることを確認:
    /path/to/your/working_copyfeature_login ブランチを指している状態であることを svn info で確認します。
  2. ワーキングコピーに未コミットの変更がない状態にする:
    もし変更があれば、コミットするか一時的に待避させます。
  3. /trunkからカレントブランチへマージを実行:
    bash
    # ワーキングコピーのルートディレクトリで実行
    $ svn merge https://your-svn-repo.com/project/trunk .

解説:

  • https://your-svn-repo.com/project/trunk: マージ元(ソース)のURLです。/trunkの変更を取得します。
  • .: マージ先(ターゲット)のパスです。. は現在のディレクトリ、つまりワーキングコピーのルートを意味します。このコマンドは、「/trunkの最新のリビジョンまでの変更を、このワーキングコピーが指すブランチに対して適用せよ」という意味になります。
  • SVNは、あなたのブランチが/trunkから分岐して以降、/trunkにコミットされた変更のうち、まだあなたのブランチにマージされていない変更を自動的に判断し、あなたのワーキングコピーに適用しようとします。この履歴追跡情報は、SVN 1.5以降で導入された svn:mergeinfo プロパティによって管理されます。
  • マージの過程で、ファイルの内容にコンフリクトが発生する場合があります。その場合は、コンフリクトを解決する必要があります(後述の「コンフリクトの解決」を参照)。

  • マージ結果の確認とテスト:
    マージによってワーキングコピーのファイルが更新されました。コンフリクトを解決し、すべての変更が正しく適用されたら、必ずビルドやテストを実行し、アプリケーションが期待通りに動作することを確認します。マージによって思わぬ不具合が発生することは少なくありません。

  • マージ結果のコミット:
    マージ操作自体はワーキングコピーに変更を加えるだけで、リポジトリにはまだ反映されていません。マージの結果(コンフリクト解決済みのファイルや、/trunkから取り込まれたファイルなど)を、あなたのブランチにコミットします。
    bash
    $ svn commit -m "Merge latest changes from trunk into feature_login branch (rXXX-rYYY)"

    コミットメッセージには、どのリビジョン範囲の変更をマージしたかを記録しておくと、後で履歴を追いやすくなります(例: リビジョンXXXからYYYまでの/trunkの変更をマージ)。SVN 1.5以降の svn:mergeinfo があれば、この情報は自動的に記録されますが、メッセージに含めるのも良い習慣です。

注意点:

  • 定期的なマージ: /trunkへのマージを計画しているブランチでは、開発期間が長くなるにつれて、/trunkの変更を取り込む頻度を検討してください。頻繁に行えば一度のマージの作業量は減りますが、マージの回数が増えます。期間が空けば一度のマージ作業量は増え、コンフリクト発生率と解決の手間が増大する傾向があります。プロジェクトの状況に合わせて適切な頻度を見つけてください。
  • マージ元のURLとマージ先のパス: svn merge コマンドは merge SOURCE_URL [TARGET_PATH] の形式です。ここでは「/trunk の変更を カレントブランチ(.) にマージする」なので、SOURCE_URL/trunk のURL、TARGET_PATH. となります。間違えないように注意してください。

このステップを経ることで、あなたのブランチは/trunkの最新の変更を反映した状態になり、最終的にブランチを/trunkにマージする際の手間やコンフリクトを減らすことができます。

ステップ7:ブランチからトランクへのマージ準備

ブランチでの開発が完了し、十分にテストが済んだら、いよいよその成果を/trunkにマージします。マージ作業を行う前に、以下の準備をしておくことが推奨されます。

  1. ブランチでの開発が完全に完了し、安定していることを確認:
    実装すべき機能はすべて実装され、既知のバグがない状態であることを確認します。テストがすべてパスしているのが理想です。
  2. 必要に応じて、ブランチを最新の/trunkの変更で更新する:
    ステップ6で説明したように、マージ直前に一度/trunkの最新の変更をブランチに取り込んでおくことで、マージ時のコンフリクトを最小限に抑えることができます。これは必須ではありませんが、大規模なブランチほど有効です。
  3. マージ先のワーキングコピーに切り替える:
    ブランチの変更をマージしたい先のワーキングコピーに移動または切り替えます。通常は/trunkのワーキングコピーです。
    “`bash
    # ワーキングコピーのルートディレクトリに移動
    $ cd /path/to/your/working_copy # もしtrunkのWCと違う場所なら

    trunkへ切り替え(もし違うブランチを指していたら)

    $ svn switch https://your-svn-repo.com/project/trunk .

    trunkの最新状態に更新しておく

    $ svn update
    ``
    **重要:**
    svn merge` コマンドは、「マージ元(SOURCE)の変更を、今いるワーキングコピー(TARGET)に適用する」という操作です。ブランチをトランクにマージしたい場合は、必ずトランクのワーキングコピーでマージコマンドを実行してください。
    4. マージ元のブランチが完全にコミットされていることを確認:
    マージしたいブランチに、未コミットのローカル変更が残っていないことを確認します。マージはリポジトリ間の変更を対象とするため、ワーキングコピー上のローカル変更はマージされません。

準備が整ったら、次のステップであるマージを実行します。

ステップ8:ブランチをトランクへマージする (svn merge)

いよいよ、完成したブランチの変更をメインラインである/trunkにマージする作業です。SVNにおけるマージは、svn merge コマンドを使用します。

SVN 1.5以降では、svn:mergeinfo プロパティによるマージ追跡機能が強化されており、これを利用するのが現代的なマージの推奨方法です。古いSVNバージョンや特定のマージ戦略(例: 一度きりのマージで、ブランチへのマージバックを行っていない場合)では、--reintegrate オプションを使用することもありますが、マージ追跡機能を使った方法の方が柔軟で安全です。

本記事では、マージ追跡機能を使ったマージ方法を主に解説し、その後 --reintegrate について補足します。

方法1:マージ追跡機能を利用したマージ(推奨)

この方法では、SVNが svn:mergeinfo プロパティを参照し、マージ元ブランチからマージ先トランクへ、まだ適用されていない変更セット(リビジョンの範囲)を自動的に判断して適用します。

手順:

  1. マージ先のワーキングコピー(/trunk)にいることを確認:
    ステップ7で準備した通り、/trunkを指すワーキングコピーのルートディレクトリにいることを確認します。svn infoURL:/trunk を指しているか確認します。
  2. マージを実行:
    以下の形式でコマンドを実行します。
    bash
    # マージ先のワーキングコピーのルートディレクトリで実行
    $ svn merge URL_OF_SOURCE_BRANCH .

    例:feature_login ブランチを /trunk にマージする場合
    bash
    $ svn merge https://your-svn-repo.com/project/branches/feature_login .

解説:

  • https://your-svn-repo.com/project/branches/feature_login: マージ元(ソース)のブランチのURLです。
  • .: マージ先(ターゲット)のパスです。カレントディレクトリである/trunkのワーキングコピーを指します。
  • このコマンドを実行すると、SVNは feature_login ブランチの svn:mergeinfo プロパティなどを参照し、どの/trunkのリビジョンが既に feature_login にマージされているか、そして feature_login ブランチ固有の変更はどれかなどを判断します。そして、まだ/trunkにマージされていない feature_login ブランチのリビジョン範囲の変更を、あなたの/trunkワーキングコピーに適用しようとします。
  • マージの過程でコンフリクトが発生することがあります。その場合は、必ずコンフリクトを解決してください(後述の「コンフリクトの解決」を参照)。

  • マージ結果の確認とテスト:
    マージが完了し、コンフリクトも解決したら、必ずビルドやユニットテスト、結合テストなどを実行し、すべてが期待通りに動作することを確認します。マージ結果のテストは非常に重要です。

  • マージ結果のコミット:
    テストが完了し、マージ結果に問題がないことを確認したら、この変更(マージによって更新されたファイル)を/trunkにコミットします。
    bash
    $ svn commit -m "Merge feature_login branch to trunk (closes #XXX)"

    コミットメッセージには、どのブランチをマージしたのか、そのブランチが解決した課題(チケット番号など)を含めると良いでしょう。このコミットによって、あなたの/trunkワーキングコピーへの変更がリポジトリの/trunkに反映されます。このコミット自体も、マージ追跡情報(/trunkfeature_login ブランチの特定のリビジョンがマージされたという情報)を含みます。

方法2:--reintegrate オプションを使用したマージ(限定的なケース)

--reintegrate オプションは、特定の単純なマージシナリオ(通常は、/trunkから切ったブランチに対し、ブランチへの/trunkからのマージバックは一度も行わず、純粋にブランチ固有の変更だけを/trunkに戻す場合)に使うことがありました。

“`bash

マージ先のワーキングコピー(/trunk)にいることを確認

$ cd /path/to/your/working_copy # trunkのWC

switchでtrunkにいるか確認&update

$ svn switch https://your-svn-repo.com/project/trunk .
$ svn update

–reintegrate マージを実行

$ svn merge –reintegrate URL_OF_SOURCE_BRANCH .
“`

注意点と推奨されない理由:

  • --reintegrate は一度実行すると、そのブランチを再度/trunk--reintegrate マージすることはできません。通常、 --reintegrate マージ後はそのブランチは役割を終えたものとして扱われます。
  • --reintegrate を使用するブランチに対して、マージ先のトランク(あるいは他のブランチ)の変更をマージバック(ステップ6の操作)していると、複雑な問題が発生したり、エラーになったりする可能性があります。
  • SVN 1.5以降のマージ追跡機能の方が、ブランチへのマージバックを頻繁に行う開発スタイルにも対応でき、より柔軟で安全です。特別な理由がない限り、マージ追跡機能を利用したマージ(方法1)を使用することが推奨されます。

結論として、現代的なSVN運用では方法1(マージ追跡機能を利用したマージ)を基本的に使用してください。 --reintegrate は過去の経緯を知るため、あるいは特定のレガシーな状況で必要になる可能性を考慮して知っておく程度で良いでしょう。

コンフリクトの解決

マージを実行する際、マージ元(ブランチ)とマージ先(トランク)で同じファイルの同じ箇所が変更されている場合などに、「コンフリクト(競合)」が発生します。コンフリクトが発生したファイルは、SVNによって特別なマーカーが付加され、どちらの変更を採用するか、あるいは両方の変更をどのように組み合わせるかを開発者が手動で判断・編集する必要があります。

コンフリクトが発生すると、svn status コマンドの出力で C マークが表示されます。

bash
$ svn status
C path/to/conflicted_file.txt
M path/to/other_file.txt # これはコンフリクトなしの変更

コンフリクトが発生したファイルを開くと、以下のようなコンフリクトマーカーが含まれています。

“`
<<<<<<< .mine
ここはあなたのワーキングコピーでの変更内容 (マージ先の内容)
=======
ここはマージ元のブランチでの変更内容

.r12345 (マージ元のリビジョン番号)
“`

または、マージの種類によっては以下のようなマーカーになることもあります。

“`
<<<<<<< .working (your modifications)
ここはあなたのワーキングコピーでの変更内容 (マージ先の内容)
||||||| .merge-left.r12345
マージ元のブランチの変更内容(マージ元のファイル)
=======
マージ先のトランクの変更内容(マージ実行前のファイル)

.merge-right.r12346
“`

コンフリクト解決の手順:

  1. コンフリクトファイルの特定: svn status コマンドで C マークが付いているファイルを確認します。
  2. コンフリクトの編集: テキストエディタでコンフリクトファイルを開き、マーカー (<<<<<<<, =======, >>>>>>>) を見つけます。
    • どちらか一方の変更を採用する場合:不要な変更とマーカー行を削除し、残したい方の内容だけを残します。
    • 両方の変更を組み合わせる場合:マーカー行をすべて削除し、両方の変更を適切に手動で組み合わせます。
    • 注意: マーカー行は必ずすべて削除してください。
  3. SVNへの解決報告: ファイルの編集が完了し、コンフリクトが解消された状態になったら、SVNに「このファイルのコンフリクトは手動で解決しました」と報告する必要があります。これには svn resolve コマンドを使用します。
    bash
    $ svn resolve --accept working path/to/conflicted_file.txt

    • --accept working: ワーキングコピー内の現在のファイル内容(手動編集後の内容)を採用するという意味です。他にも base, mine, theirs-full, theirs-conflict など様々なオプションがありますが、手動編集した場合は working を使うのが一般的です。
    • -R オプションを付けて再帰的に解決することも可能ですが、どのファイルを解決したか把握するためにも、最初はファイルごとに実行するのがおすすめです。
  4. 解決状態の確認: 再度 svn status コマンドを実行し、コンフリクトファイルから C マークが消えていることを確認します。M マーク(変更済み)になっていれば正常です。
  5. 他のコンフリクトも同様に解決: 他に C マークのファイルがあれば、1〜4のステップを繰り返します。
  6. マージ結果全体のテスト: すべてのコンフリクトを解決したら、必ずビルドやテストを実行し、全体の動作を確認します。

マージツール:

複雑なコンフリクトの場合は、Diff/Mergeツールを使うと視覚的に分かりやすく解決できます。TortoiseSVNなどのGUIクライアントには統合されたツールが付属しています。コマンドラインでも、svn resolve --launch path/to/conflicted_file.txt コマンド(環境設定が必要)で外部ツールを起動できます。

コンフリクト解決はマージ作業の中でも最も手間と注意が必要な部分です。落ち着いて、慎重に進めてください。不明な場合は、チームメンバーに相談しましょう。

ステップ9:マージ後のアクション

ブランチから/trunkへのマージが完了し、コミットも成功したら、通常は以下のいずれか、あるいは両方のアクションを行います。

  1. 使用済みブランチの削除(任意だが一般的):
    マージが完了し、そのブランチがもう必要なくなった場合、リポジトリから削除することができます。これはリポジトリを整理し、混乱を防ぐために一般的です。
    “`bash
    # 削除したいブランチのURLを指定して実行
    $ svn delete https://your-svn-repo.com/project/branches/feature_login \
    -m “Delete merged feature_login branch”

    成功した場合の出力例

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

    ``
    **重要:** SVNにおける
    deleteコマンドは、ファイルシステム上の物理的な削除とは異なり、**リポジトリの履歴から完全に抹消するわけではありません**。単にその時点でのディレクトリツリーからそのパスが「削除された」という状態を記録するだけです。過去のリビジョンを辿れば、削除されたブランチの内容や履歴をいつでも参照したり、復旧したりすることが可能です。安心して削除できます。
    リポジトリブラウザや
    svn listコマンドで確認すると、該当のブランチが表示されなくなっているはずです。
    ワーキングコピーから削除されたブランチを指していたディレクトリは、
    svn update` を実行するとSVN管理下から外れます(ローカルに残るか削除されるかはクライアントの設定によりますが、通常は削除されます)。

  2. タグの作成(リリースブランチのマージ後など):
    もしマージしたブランチがリリース準備のためのブランチ(例: release_1.0)であり、そのマージ結果がリリースバージョンになる場合、/trunkにマージした時点、またはマージ元となったリリースブランチの最終状態を基に、/tags ディレクトリにタグを作成することが一般的です。
    タグは特定の時点での安定した状態を記録し、後から参照したり、必要であればその状態からブランチを切ってバグ修正(ホットフィックス)を行ったりするために使用します。
    タグもブランチと同様に svn copy コマンドで作成します。タグは通常、/trunkまたはリリースブランチの特定のリビジョンから作成されます。

    • /trunkにマージしたコミット(最新リビジョン)からタグを作成する場合:
      bash
      # マージ先の`/trunk`のURLを指定
      $ svn copy https://your-svn-repo.com/project/trunk \
      https://your-svn-repo.com/project/tags/v1.0.0 \
      -m "Tag version 1.0.0 after release branch merge"
    • マージ元となったリリースブランチの最終リビジョンからタグを作成する場合:
      bash
      # マージ元のリリースブランチのURLを指定
      # 必要に応じて特定のリビジョン番号も指定 (@XXX)
      $ svn copy https://your-svn-repo.com/project/branches/release_1.0 \
      https://your-svn-repo.com/project/tags/v1.0.0_from_release_branch \
      -m "Tag version 1.0.0 from release branch final state"

      タグの作成は、単なるコピー操作であり、それ自体が開発作業を伴うものではありません。一度作成されたタグは、通常変更されることはありません。

これらの後処理を行うことで、リポジトリの構造が整理され、今後の開発やリリース管理が容易になります。

高度なトピックとトラブルシューティング

本記事で基本的なブランチ・マージ手順は網羅しましたが、SVNのマージにはさらに複雑なシナリオや注意点があります。

マージ追跡(Merge Tracking)の理解 (svn:mergeinfo)

SVN 1.5以降で導入されたマージ追跡機能は、svn:mergeinfo というプロパティを使用して、どのリビジョンがどこからどこへマージされたかをリポジトリ内部で記録する仕組みです。

  • svn:mergeinfo プロパティは、ディレクトリに対して設定されます。
  • 例えば、/branches/feature_login/trunk の変更をマージすると、/branches/feature_login ディレクトリに svn:mergeinfo プロパティが設定され、「/trunk からリビジョンXXX-YYYがマージ済みである」といった情報が記録されます。
  • この情報があるおかげで、svn merge コマンドは次にマージすべきリビジョン範囲を自動的に判断できます。
  • svn propget svn:mergeinfo URL_OR_PATH コマンドでマージ情報を参照できます。
  • svn mergeinfo --show-revs eligible SOURCE_URL TARGET_PATH コマンドで、マージ可能なリビジョン(まだマージされていないリビジョン)を確認できます。
  • svn mergeinfo --show-revs merged SOURCE_URL TARGET_PATH コマンドで、既にマージされたリビジョンを確認できます。

マージがうまくいかない場合、この svn:mergeinfo の状態を確認することが原因究明の第一歩となることがあります。

部分的なマージと不要なリビジョンのスキップ

特定の変更セット(リビジョン)だけをマージしたい場合や、一部のリビジョンをスキップしてマージしたい場合があります。これには svn merge -c リビジョン番号 URL_OF_SOURCE という形式を使用します。

  • 特定のリビジョン(チェンジセット)のみマージ:
    例えば、/trunk のリビジョン 1234 で行われたバグ修正だけをブランチに取り込みたい場合(いわゆるCherry-pickingに類似)。
    bash
    # ワーキングコピーはマージしたいブランチを指していること
    $ svn merge -c 1234 https://your-svn-repo.com/project/trunk .

    または、リビジョン範囲で指定することもできます。リビジョン1234から1235までの変更をマージ(これは実際にはリビジョン1235のコミット内容を指す):
    bash
    $ svn merge -r 1234:1235 https://your-svn-repo.com/project/trunk . # r1234は親リビジョン、r1235がターゲット

    より直感的にはチェンジセット指定 svn merge -c 1235 https://... が推奨されます。
  • 特定のリビジョンをスキップしてマージ:
    例えば、/trunk の最新までマージしたいが、リビジョン 1234 で導入された不安定な変更だけは除外したい場合。-c オプションでマイナスのリビジョン番号を指定すると、そのリビジョンの変更を「元に戻す」操作としてマージに含めることができます。
    bash
    # 例えば r1000からHEADまでマージしたいが、r1234だけは除く場合
    # まず全体をマージ(コンフリクト解消含む)
    $ svn merge -r 1000:HEAD https://your-svn-repo.com/project/trunk .
    # 次に、スキップしたいリビジョンを元に戻すマージを行う
    $ svn merge -c -1234 https://your-svn-repo.com/project/trunk .
    # 最後に結果をテストしてコミット

    スキップは慎重に行う必要があります。依存関係がある変更をスキップすると、予期せぬ不具合の原因になります。

マージのやり直しや取り消し(Revert)

マージを実行した結果、予期しない問題が発生したり、マージ自体が不要になったりする場合があります。その場合、マージコミットを「元に戻す(リバート)」ことができます。

svn merge -c -リビジョン番号 URL_OF_TARGET_OR_COPY コマンドを使用します。ここで指定するリビジョン番号は、マージを実行してコミットした時のリビジョン番号です。

例:/trunk でリビジョン 12345 としてコミットされたマージを取り消したい場合。

“`bash

マージ先(/trunk)のワーキングコピーにいることを確認

$ cd /path/to/your/working_copy # trunkのWC

マージコミットを取り消すマージを実行

$ svn merge -c -12345 .

または、簡潔に

$ svn merge -c -12345 https://your-svn-repo.com/project/trunk . # trunkのURLを指定してもOK

成功した場合の出力例

U path/to/some/file.txt (Updates)

D path/to/some/other/file.txt (Deletes)

“`

解説:

  • -c -12345: リビジョン 12345 でコミットされた変更セットを逆方向に適用するという意味です。
  • このコマンドは、リビジョン12345のコミットで適用されたすべての変更を打ち消すような変更をワーキングコピーに適用します。
  • マージと同様に、この操作でもコンフリクトが発生する可能性があります。発生した場合は同様に解決します。
  • コンフリクト解決やテストが完了したら、この変更を新しいリビジョンとしてコミットします。
    bash
    $ svn commit -m "Revert merge of feature_X branch (committed in r12345)"

これで、リビジョン12345でのマージによる変更が論理的に打ち消された状態になります。

ブランチの名前変更や移動

svn rename (または svn move) コマンドは、リポジトリ内のファイルやディレクトリの名前を変更したり、移動したりするために使用されます。これはブランチやタグに対しても使用できます。

“`bash

ブランチの名前を変更する例

$ svn rename https://your-svn-repo.com/project/branches/old_branch_name \
https://your-svn-repo.com/project/branches/new_branch_name \
-m “Rename old_branch_name to new_branch_name”
“`

これも svn copy と同様にリポジトリ内でのメタデータ操作であり、高速です。ただし、名前やURLが変わるため、そのブランチのワーキングコピーを使っているチームメンバーは svn switch --relocate OLD_URL NEW_URL コマンドなどでワーキングコピーを新しいURLに追従させる必要があります。

ブランチとマージのベストプラクティス

SVNにおけるブランチとマージを成功させるために、いくつかのベストプラクティスがあります。

  • 標準的なリポジトリ構造 (/trunk, /branches, /tags) を使用する: ツールとの親和性が高く、チーム内の共通理解を促進します。
  • ブランチの目的を明確にする: 何のためのブランチなのかを明確にし、名前に反映させます(例: feature/login, bugfix/issue123, release/1.0.0)。
  • ブランチの寿命を短く保つ: 長期間にわたるブランチは、/trunkとの差分が大きくなり、マージ時のコンフリクトが激しくなる傾向があります。可能であれば、開発期間を短く設定し、早めに/trunkへマージすることを目指します。
  • 定期的に/trunkの変更をブランチにマージする: 長期間開発するブランチでは、マージを計画している/trunkの最新の変更を定期的にブランチに取り込む(ステップ6)ことで、最終的なマージ時のコンフリクトを軽減できます。
  • マージ前にブランチを安定させる: マージ元のブランチは、テストが十分に実施され、安定した状態であることが望ましいです。不安定な状態でのマージは、/trunkに問題を持ち込むリスクを高めます。
  • マージコミットはまとめる: ブランチでの複数のコミットを、最終的に/trunkにマージする際には、原則としてマージ追跡機能が差分をまとめて適用します。マージ結果をコミットする際は、それが「どのブランチの、どのような目的の変更をマージしたコミットであるか」が分かるようなメッセージを記述します。
  • マージ後は必ずテストを行う: マージ作業そのものによって予期しない問題が発生することがあります。マージ結果をコミットする前に、必ずビルドとテストを実行し、アプリケーションが正常に動作することを確認します。
  • コンフリクト解決を怖がらない、かつ慎重に行う: コンフリクトはマージにつきものです。落ち着いて、ファイルの内容を理解し、正しい解決策を適用します。不明な場合は一人で抱え込まず、他のチームメンバーに相談します。マージツールを積極的に活用しましょう。
  • タグは変更しない: /tags 以下のパスは、特定の時点の「スナップショット」であり、変更しないというルールをチームで徹底します。バグ修正が必要な場合は、タグからブランチを切って行います。
  • 使用しなくなったブランチは削除する: マージが完了し、もう開発に使用しないブランチは、リポジトリを整理するために削除します(論理的な削除なので履歴は残ります)。

これらのベストプラクティスを実践することで、SVNを使ったブランチ/マージワークフローをより効率的かつ安全に進めることができます。

まとめ

本記事では、SVNにおけるブランチ作成からマージ、そしてその後の処理に至るまでの一連の手順を詳細に解説しました。

  1. ブランチ作成の目的を明確にする: 新機能、バグ修正、リリース準備など。
  2. 作成元を選択する: 通常は /trunk、あるいは既存のブランチやタグ。
  3. svn copy でブランチを作成する: リポジトリURL間でのコピーが推奨。高速で履歴が保存される。
  4. svn switch でブランチのワーキングコピーへ切り替える: 既存のワーキングコピーを効率的に更新。
  5. ブランチ上で開発作業を行う: 通常のSVN操作 (update, add, commit など)。他のブランチに影響しない独立した作業。
  6. (推奨)定期的に/trunkの変更をブランチにマージする: 最終マージ時のコンフリクトを軽減するため。svn merge URL_OF_TRUNK . を使用。
  7. ブランチからトランクへのマージ準備を行う: ブランチの安定化、マージ先のワーキングコピーへの切り替え(通常/trunk)、最新状態への更新。
  8. svn merge でブランチをトランクへマージする: SVN 1.5以降のマージ追跡機能を利用した svn merge URL_OF_BRANCH . が推奨。--reintegrate は限定的なケース。
  9. コンフリクトを解決する: マージ中に発生した場合は、手動編集やツールで解決し、svn resolve でSVNに報告。
  10. マージ結果をテストし、コミットする: 動作確認を必ず行い、問題なければ/trunkにコミット。
  11. マージ後のアクション: 使用済みブランチの削除 (svn delete) や、必要に応じたタグの作成 (svn copy)。

SVNのブランチとマージは、最初は複雑に感じるかもしれませんが、その仕組みと手順を理解し、繰り返し実践することで習得できます。特にマージ追跡機能の導入により、以前よりも安全かつ柔軟なマージが可能になっています。

この記事が、あなたがSVNを使ったチーム開発において、ブランチとマージを効果的に活用し、プロジェクトを成功に導くための一助となれば幸いです。安全で効率的なバージョン管理を実践していきましょう。


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール