疑似マージ

チェリーピッキング

時々、ブランチの変更の全部ではなく一部だけを選んでマージすることが便利であることがあります。 これは一般的に チェリーピッキング(cherrypicking) として言及されます。

チェリーピッキングが役に立ついくつかの事例:

  • メインの開発ブランチから修正の一部を取り出してリリースブランチに取り込む
  • 実験ブランチから改善内容を選別して機能ブランチに取り込む

foo ブランチのリビジョン Xによってなされた変更のみをマージするためには:

bzr merge -c X foo

foo ブランチのリビジョンXまでの変更のみをマージするためには:

bzr merge -r X foo

foo のリビジョンX以降の変更のみをマージするためには:

bzr merge -r X.. foo

foo ブランチのリビジョンXからリビジョンYまでの変更のみをマージするには:

bzr merge -r X..Y foo

通常のマージと同じように、チェリーピックは明示的にコミットしなければなりません。 これを行う前に、 bzr diff を利用した変更を見て何かあればテストスイートを実行するとよいでしょう。

通常のマージとは異なり、Bazaarは現在はチェリーピックを追跡しません。 具体的に言うと、変更は通常のコミットと同じようになり、他のブランチから来た(内部の)変更履歴は失われます。 上記のようなチェリーピックが役に立つ場面では、このことはたいてい重大な問題ではありません。 フルマージが後で行われることはけっしてないと言える十分な理由があるからです。 そうではない場面では、変更が再びマージされたときにまた衝突を解消する必要があります。

親のないマージ

チェリーピックに関連したテクニックとして、マージ元のリビジョンを参照せずに、 コミット前に親リビジョンを忘れることができます。 こうすると、このマージで行われた全ての変更が、1回のコミットで行われたような 効果があります。 マージしたあと、コミットする前に次のコマンドを実行します。

bzr revert --forget-merges

これで、作業ツリー内の変更は残したまま、その変更がどこからマージされたかの 記録だけを削除します。そして、次のコミットではマージされたリビジョンに 関する情報が一切ない状態で、全ての変更を記録します。

この機能は、「きれいな」履歴を作りたいユーザーに取って便利なものですが、 Bazaarはもともとマージされた履歴を段階的に表示する機能を持っているので、 失った履歴の価値が履歴のきれいさの価値を上回らないように気をつける必要があります。 特に、この機能を使うとマージ元の変更だけを取り込んでその変更のマージ元を 記録しないので、後で同じマージ元からマージしようとすると余計なコンフリクトを 発生させる可能性があります。

リバースチェリーピッキング

チェリーピッキングは一連の変更を元に戻すことができます。この場合、リビジョン範囲の上界(upper bound)が下界(lower bound)よりも 小さく なります。 たとえば、リビジョン10の変更を取り消すためのコマンドはこうなります:

bzr merge -r 10..9

どこかから、すべてではない大半の変更を得たい場合通常のマージをした後に少しのリバースチェリーピックを行うとよいでしょう。

コミットされていない変更をマージする

複数のブランチを持っており、間違えて別のブランチを変更し始めた場合、訂正をとるステップは次のとおりです。 ブランチ bar で作業したかったのに、ブランチ foo で作業を始めてしまったという場合を前提とします:

  1. bar ブランチに移動する
  2. bzr merge --uncommitted foo を実行する
  3. やってくる変更をチェックする (bzr diff)
  4. foo ブランチに変更する
  5. bzr revert を実行する

リベースする

通常のマージの別のオプションは リベース(rebase) です。 すなわち、現在のブランチが本来とは異なる地点をベースにするようにします。 リベースは rebase プラグインによって提供される rebase コマンドによってサポートされます。

rebase コマンドは現在の作業ディレクトリ内のリベースされるブランチ上で別のブランチの位置をとります。 ブランチが指定されないと親のブランチが使われ、通常これは望まれる結果です。

最初のステップは現在のブランチのものであるが親のブランチではないリビジョンを特定することです。 現在のブランチはターゲットブランチと同じリビジョンに設定され、それぞれのリビジョンはブランチのトップで再現されます。 プロセスの終了時に現在のブランチがターゲットの最終リビジョンからブランチされたようになります。

再現されるそれぞれのリビジョンがツリーの中で衝突を起こすことがあります。 これが起きたらコマンドは停止してそれらを修正しなければなりません。 merge するためにコミットを解消し、それらが解消されたものとしてマークするために bzr resolve を実行します。 すべての衝突を解消したら、リベースオペレーションを続けるために bzr rebase-continue を実行します。 衝突に遭遇せず続けないことを決めたら、 bzr rebase-abort を実行できます。 リプレイされるコミットの一覧を表示するために rebase-todo を利用することもできます。

注: マージトラッキング機能が貧弱なVCSツールから来たユーザーの中にはリベースを好む人がいます。 古いツールでの作業方法に似ている、もしくは”完璧にきれいな” 履歴が重要だからです。 Bazaarでリベースする前に、通常のマージがベターな選択肢ではないのか考えてください。 とりわけ、始める前にプライベートなブランチをリベースするのは大丈夫ですが、 他の誰かとブランチを共有した後のリベースは 強く非推奨 です。