rebase で本番用の設定と開発用の設定を簡単に切り替える

rebase を使うと、本番用の設定と開発用の設定を簡単に切り替えることができます。
rebase の基本は
rebase について - ぐるぐる〜
で説明しているので、ここまでは分かっている前提です。


例えば、ASP.NET で本番用と開発用の web.config が違うとします。
共用のリポジトリには開発用の web.config をコミットしてはいけません。
これをすべて手作業で行おうとすると、ついつい間違って開発用の web.config をコミットしてしまったり、ついつい間違えて開発用の web.config の内容がどこかにいっちゃったりすることがあります。
こういった事故を少なくするために、rebase を使います。

rebase --onto

onto オプションを使用することで、ある地点 (ブランチ a とします) から分岐したブランチ (b とします) の分岐点から先のみを任意の地点 (ブランチ base とします) に付け替えることができます。
言葉で説明するより、図を見てもらった方が分かりやすいでしょう。


最初の状態はこんな感じです。

            i---ii b
           /
      A---B a
     /
1---2---3 base

まずは onto オプションを使用しない通常の rebase です。

$ git rebase base b

を実行すると、

      A---B a  A---B---i---ii *b
     /        /
1---2--------3 base

となります。

次に、onto オプションを使用した rebase です。

$ git rebase --onto base a b

を実行すると、

      A---B a  i---ii *b
     /        /
1---2--------3 base

となります。
onto オプションを使用しない場合と比べると、ブランチ b で行ったコミットのみが rebase されているのがわかります。

rebase --onto による本番用設定と開発用設定の切り替え

rebase --onto を使うことで、本番用設定と開発用設定を簡単に切り替えることができるようになります。
まず、本番用設定は普通にコミットしておきます。
そして、for-dev ブランチを作成し、開発用設定への変更のみを行ったコミットを作成します。
例えば開発用の設定では、動作確認用の DB への接続文字列を設定したとします。

$ git checkout -b for-dev
$ vim web.config
$ git commit -am "configuration for dev"

状態としては、

      C *for-dev
     /
A---B master

こんなイメージです。
開発が進むと、色々なトピックブランチが生成されます。

      C for-dev   G---H *topic-1
     /           /
A---B---D---E---F master

ここで、実際に DB に接続して動作確認が行いたくなったとします。
この時に、for-dev ブランチを topic-1 ブランチの先頭に付け替えれば、設定ファイルが開発用のものになります。

$ git rebase --onto topic-1 for-dev^ for-dev

このコマンドを実行することで、

                        C *for-dev
                       /
                  G---H topic-1
                 /
A---B---D---E---F master

の状態になります。
ここで、for-dev^ とありますが、これは for-dev の一つ前のコミット、つまり B のコミットを表します。
for-dev ブランチでの動作確認が終ったら、今度は topic-1 に戻ります。

$ git checkout topic-1

これで、本番用の設定に切り替わりました。

                        C for-dev
                       /
                  G---H *topic-1
                 /
A---B---D---E---F master

master ブランチに merge してリモートのリポジトリに push しても安心です。

$ git checkout master
$ git merge topic-1
$ git branch -d topic-1
$ git push
                  G---H---C for-dev
                 /
A---B---D---E---F---G---H *master

さらに開発が進んで、

       G---H---C for-dev   L topic-2
      /                   /
略---F---G---H---I---J---K master

となり、topic-2 で開発用の設定に切り替える場合、

$ git rebase --onto topic-2 for-dev^ for-dev

です。

                             C *for-dev
                            /
                           L topic-2
                          /
略---F---G---H---I---J---K master

このように、最後は常に for-dev^ for-dev なので、簡単ですね!


更に for-dev を merge できないようにすることもフックスクリプトを使えば可能だとは思うのですが、そこまではやってません。
そう言う操作は「何かおかしい」感が強いため、そこでミスすることは考えにくいので。
あ、いや、決して面倒なわけでは・・・