svnmerge
svnmerge.py は、自動ブランチ管理のためのツールです。
ブランチからのマージあるいはブランチへのマージを簡単に行えるように、
また自動的にどのリビジョンをマージしたかを記録してくれるツールです。
常にまだマージしていないリビジョンのリストを表示できます。そして
二度同じ変更をマージしてしまう等の間違いをしないようにできます。
svnmerge は Subversion ブランチで、どのリビジョンが既にマージされたかを
記録するための yellow sticky notes と考えてください。
さらに、それらの情報を、閲覧したり、管理したり、更新したりするための
有益な機能を提供しています。
詳しくは機能リストを見てください。
機能
-
Merge tracking サポート : どのリビジョンが既にマージされたかを覚えていて、
デフォルトで正しい動作(新しいリビジョンだけをマージする)を行います。
-
開発ブランチ用に、"すべてマージ" コマンドをサポートします。
-
リリースブランチ用に、"cherry-picking" コマンドをサポートします。
cherry-picking とは特定のリビジョンまたは特定の範囲のリビジョンを
選択してマージすることを指します。
-
マージ可能なリビジョン番号、コミットログ、変更点をリストアップできます。
-
双方向マージ(Bidirectional merges) : ブランチと最新バージョン間で双方向マージができます。
-
Multiple heads support : 複数ソースからのマージに対応します。これは例えば
複数のブランチを管理していて、その修正を trunk にマージする場合に有益です。
-
Revision blocking: ブランチの修正で、マージしたくないリビジョンを記録することが
てきます。マージしたくないリビジョンのことを忘れてしまっても決してマージしない
ようにできます。
-
Merge rollbacks: どんな修正を行った場合でも自由に変更を元に戻せます。
-
完全にコミットは自由 : コミットは自分で行うようにしなければいけないので
svnmerge.py の修正をレビューすることができます。
-
コミットログに関する提案 : 自動的にマージしたリビジョンのコミットログのリストが
テキストファイルとして作成されます。良いコミットメッセージの提案として利用できます。
-
手動マージ : 手動でいくつかの変更をマージした場合、svnmerge.py に merge tracking
情報の更新をさせることができます。
FAQ
-
svnmerge.py はどんな問題を解決しますか? もし同じ修正を別のブランチに
適用しなければいけないときに、Subversion は既にそのための方法を持っています。
伝統的な Subversion は変更をマージしてくれます。しかし、あなたが
どれをマージしたかを覚えてくれません。既にマージした変更を除外するための
便利な方法を提供してくれません。 svnmerge.py はこの仕事を自動化してくれます。
さらに、それを簡単にしてくれます。 svnmerge.py はマージしたすべてのリビジョンの
コミットログ用のメッセージを作成してくれます。
-
だれかが svnmerge.py を使おうとする場合、すべての人が svnmerge.py を使わなければ
ならないように聞こえます。言い換えれば手動マージを行うと svnmerge.py が追跡しようと
しているものを破壊しますか?
手動マージは merge-tracking 情報を破壊しません。でも svnmerge.py の恩恵を与え
ないということを意味します。でも手動で行った変更に対して いったん svnmerge を
行うと、その修正は マージされたということが記録されます。それ以降は svnmerge.pyは
再度マージを試みることはありません。
-
なぜ同じ修正を二度マージすることが問題となるのですか? Subversion はそんなことは
気にしないようです。ワーキングコピーには、私が一度マージしたときと比べてそれ以外の
修正は含まれていませんでした。
同じ修正を二度マージすることは通常問題になりません。以下の2つの状況で問題と
なります。
1. 特定の修正をマージしたくない場合。この場合、マージするたびに毎回特定のリビジョンを
除外する必要があります。
2. trunk と branch がかけ離れている場合。開発者A が trunk の10行目に修正を行い、
開発者B が branch の 10 行目に修正を行うとします。これらの修正はコンフリクトを
起こします。繰り返しマージを行う場合、マージを行うたびに毎回コンフリクトを解決
する必要があります。
-
branch から trunk に修正をマージして、後で branch から trunk にマージする場合、
Trying to add new property 'svnmerge-integrated' with value 'xxx' but property
already exists with value 'yyy' というエラーになります。
この問題を回避するためには、http://tinyurl.com/3c229c のパッチを適用して、
'svn resolved' を行ってください。ただしこのパッチにはいくつか大惨事が
発生することがあります。詳しくは http://tinyurl.com/39h6x5 を見てください。
システム要件
以下が最低のシステム要件です。
-
SVN のコマンドラインクライアント(svn.exe のこと)。(version 1.1 かそれ以降のバージョン)
もっと古いバージョンでも動くかもれませんが、全然テストしてません。
コマンドラインクライアントが必要なことに注意が必要です。もし TortoiseSVN を使って
いるなら、 svnmerge.py を使うためには、Subversion の公式パッケージが必要になります。
確認のために、コマンドプロンプトから以下のコマンドを実行してください。
svn --version
もしこれが動作しなければ、svnmerge.py を動作させる前に Subvesion をインストール
する必要があります。
Python 2.0 かそれ以降のバージョン
svnmerge.py を実行するために必要です。Windows の場合、Python のインストールが
必要ないバイナリバージョンの svnmerge.exe を使用する方法もあります。
Downloads
svnmerge.py は Subversion と同じリポジトリで管理されています。
適切なリリースプランや開発ロードマップはありません。なので公式リリースもありません。
svnmerge.py は Subversion がリリースされる時に一緒にリリースされます。なので trunk バージョンが
おすすめです。かなり大規模なテストスートがあるので、trunk バージョンはほとんどの場合、
安定であると信じてます。
メーリングリスト
svnmerge.py 用のメーリングリストがあります。
詳しくは
http://www.orcaware.com/mailman/listinfo/svnmerge を参照してください。
このメーリングストは、現在の開発や新機能に関する情報を得られる場所です。
Quick Usage Overview
-
branch ディレクトリで merge tracking を初期化するために、
svnmerge init
を使います。
-
マージで利用可能なリビジョンを確認するのに、
svnmerge avail
を使います。
-
branch からのいくつかのリビジョンあるいはすべてのリビジョンをマージするのに
svnmerge merge
を使います。
-
svn commit
でマージした修正をコミットします。
-
step 2 に戻って、繰り返します。
Quick tutorials
2つの一般的な利用方法のチュートリアルを説明します。
svnmerge.py がどのような動作するかを 感じてもらうためのものです。
どのように動作するか理解することにより、完全なマニュアルを読みたく
なるようにします。
開発ブランチ
このチュートリアルでは、最近trunk から作成した開発ブランチで作業を
行っていることを想定します。つまり trunk から何も変更をマージしていない
状態であることを仮定します。
-
ブランチの、何も修正していない作業ディレクトリ(pristine working copy) の
トップディレクトリに移動します。svnmerge.py は常にこの条件で実行することを
意味します。
-
merge tracking サポートを初期化します。
$ svnmerge.py init
このコマンドは、ブランチの履歴から、いつブランチが作成されたかを調べて
merge tracking サポートを初期化します。これは svnmerge.pyを使おうとしていめブランチに
対して一度だけ実行する必要があります。
svnmerge.py は決してコミットを行いません。なので今度はあなたの番です。
自動生成されたファイルを使用することができます。
$ svn ci -F svnmerge-commit-message.txt
$ rm svnmerge-commit-message.txt
好きなコミットログを入力することもできます。
trunk から branch にすべてをマージするために必要なのは以下のようにします。
$ svnmerge.py merge
これで終わりです。これで、マージをレビューして、コンフリクトがあれば修正して
コミットします。マージしたすべてのリビジョンのログを含む(かなり長い)メッセージが
利用できます。これは多くの方が便利だとわかります。
最後の step を trunk から新しい修正をマージしたいと思うたびに繰り返します。
もしtrunk からマージできる変更が、利用できるか確認したい場合、以下のようにします。
$ svnmerge.py avail # リビジョン番号だけ表示
$ svnmerge.py avail --log # リビジョンログを表示
$ svnmerge.py avail --diff # リビジョンの修正を表示
Release branches
このチュートリアルでは、trunk から最近作成したリリースブランチで作業していることを
想定します。このブランチでは以前に何の修正もマージされていないとします。
リリースブランチとは、通常リリースを安定化するためにされます。特定の限定した修正
のみが trunk からマージされて、それ以外の修正は無視されます。
-
ブランチの、何も修正していない作業ディレクトリ(pristine working copy) の
トップディレクトリに移動します。svnmerge.py は常にこの条件で実行することを
意味します。
merge tracking サポートを初期化します。
$ svnmerge.py init
このコマンドは、ブランチの履歴から、いつブランチが作成されたかを調べて
merge tracking サポートを初期化します。これは svnmerge.pyを使おうとしていめブランチに
対して一度だけ実行する必要があります。
svnmerge.py は決してコミットを行いません。なので今度はあなたの番です。
自動生成されたファイルを使用することができます。
$ svn ci -F svnmerge-commit-message.txt
$ rm svnmerge-commit-message.txt
好きなコミットログを入力することもできます。
trunk から branch にマージ可能な変更を確認します。
$ svnmerge.py avail # リビジョン番号だけ表示
$ svnmerge.py avail --log # リビジョンログを表示
$ svnmerge.py avail --diff # リビジョンの修正を表示
リリースブランチにマージしたいリビジョンを指定したい場合、マージを
行うときに以下のコマンドを使います。
$ svnmerge.py merge -r4500,4671,4812
変更点を確認して、コミットします。自動的に作成されたコミットメッセージ(svnmerge-commit-message.txt)
では、マージしたリビジョンのログを引用します。もちろんこれらのリビジョンは
svnmerge.py avail
によって表示されるリストから消えます。
特定のリビジョンをブランチに統合したくない場合、"blocked" としてマークできます。
$ svnmerge.py block -r6456-6460,6881
そしてコミットします。これらのリビジョンは
svnmerge.py avail
によって
表示されるリストから消えます。これにより、この修正を毎回レビューする必要がなくなります。
最後の2 step を
svnmerge.py avail
のリストが最小限になるまで繰り返します。
ブランチから trunk へのマージ (merge back)
このチュートリアルでは、trunkから分岐したactive ブランチを持っていると
想定します。このブラントで修正を行い、この修正を trunk にマージしたいと
いう状況を仮定します。
-
trunk の、何も修正していない作業ディレクトリ(pristine working copy) の
トップディレクトリに移動します。svnmerge.py は常にこの条件で実行することを
意味します。
-
特定のブランチに関連して、trunk の merge tracking サポートを初期化します。
$ svnmerge.py init BRANCH_URL
ここで、BRANCH_URL はブランチのフルURL です。例えば
https://server/svn/project/branches/1.0
などです。
merge back したいブランチごとに一度実行する必要があります。
もし r22788 より古いバージョンの svnmerge.py を使っている場合、リビジョンの範囲を
指定する必要があります。(あるいは単に svnmerge.py をバージョンアップして!!)
その場合、以下の手順に従う必要があります。
-
以下のコマンドでブランチが作成されたリビジョンを見つけます。
svn log --stop-on-copy BRANCH_URL
最後に表示されたりビジョンが、ブランチが作成されたリビジョンです。
-
trunk で merge tracking サポートを初期化します。
svnmerge.py init BRANCH_URL -r1-NNNNN
ここで、NNNNN は前のステップで見つけたリビジョンです。
以下のコマンドを利用して、merge-tracking の初期化結果をコミットします。
$ svn ci -F svnmerge-commit-message.txt
$ rm svnmerge-commit-message.txt
ブランチ全体をtrunk にマージしたい場合、単に以下のようにできます。
$ svnmerge.py merge --bidirectional
もしかしたらこのコマンドで、エラーが発生して、曖昧さを取り除くために -S ( --head) オプション
を使うように言われるかもしれません。trunk で、同時に複数のブランチを追跡している場合に
この問題が発生します。その場合、以下のようにしてください。
$ svnmerge.py merge --bidirectional -S BRANCH_NAME
ここで、BRANCH_NAME は、あいまいさを取り除くために有益な文字列です。あるいは完全な URL でも
構いません。--bidirectional オプションは、もしそのブランチが svnmerge.py で管理されている
場合に有効です。実際には、svnmerge.py は trunk からブランチにマージした修正(reflected revision
と呼ぶ)を自動的に無視するために解析を行います。
もし、いくつかの修正 あるいはリビジョンの範囲を cherry-pick しようとする場合
リリースブランチでのアドバイスに従うことができます。Make sure to always use
--bidirectional to all avail and merge command you issue to ignore reflected revisions.
ブランチでの作業が終わってブランチを閉じる場合、trunk からmerge tracking サポートを
取り除くことができます。
$ svnmerge.py uninit -S BRANCH_NAME
これは、マージに利用可能なブランチの数を減らして。-S オプションの利用を最小限にすることが
できる点で有用です。
ブランチを閉じるのも良い習慣です。
$ svn rm BRANCH_URL -m "branch is now closed"
閉じたブランチを特定のディレクトリに移動することで、変わった理由で
ブランチを削除したくない人もいます。
Handy Usage Tips
リビジョンリストはカンマで区切られた範囲として指定されます。(例: 1412-1419,1423,1427,1433-1440)
リビジョン範囲は、重なりあうかもしれないし、順番通りになっていないかもしれません。
svnmerge.py は自動的にこれを正規化します。
なので、 1413-1417,1410-1414,1402,1401 は 1401-1402,1410-1417 と同等です。
svnmerge は決してコミットしません。常に最後のステップをあなたに残します。
もし最初に戻りたい場合、svn revert -R
を使ってください。
でも、svn revert
はマージによって追加されたファイルを削除しないので、
完全に元に戻るためには、いくつかのファイルを自分自身で削除する必要があるかもしれません。
svnmerge merge
はブランチディレクトリで目立った変更がないことを前提に
しています。さもなければ、最新バージョンにない修正を偶然マージしてしまうかもしれません。
このチェックを上書きするためには、 --forceオプションを使ってください。
不連続なリビジョン範囲のマージは、コンフリクトやマージ漏れが発生する可能性があります。
これは、不連続マージに固有のものです。
例えば、リビジョン X であるファイルを修正する場合を考えます。そのファイルは
Y < X となるような以前のリビジョンで作成されたものとします。そしてこれまでに
マージしたことがないとします。svnmerge からの出力に特別の注意を払ってください。
これは、svn merge
の出力に由来しています。ここで "ignoring" と
いうメッセージは、実際のコンフリクトを表しています。これは、対象ブランチで
対象ファイルが存在していないので、Subversion が コンフリクトを表す "C" として
マークできないからです。
このような場合、コミットログに例えば "Note: patch to foo/bar.c in r1234 not included"
のようなログを入れておくのがいいです。