Mercurialで別オリジンのリポジトリ間の同期を取る運用の仕方について

前説

DjangoでWebアプリを開発していて自分はJavaScript部分を担当しています。
で、サーバ側を動かさないと開発できないのは辛いので、
サーバサイドで生成されたHTMLとJSONwgetして、js/dummy/とかに配置し、
各種URLの参照を書き換えてローカルでJavaScriptだけもりもり実装できるようにしました。


サーバサイドの実装に先行してJavaScriptの実装を進めていたため、
プロジェクト全体(django-apps)と独立してバージョン管理したかったため、
static配下だけが入ったdjango-staticというリポジトリを作成し、
そちらで開発を進めていきました。

今回の話は、プロジェクト全体(django-apps)とJavaScript&CSSだけ(django-static)の
二つのリポジトリの同期をとって運用していく話です。

準備

hg clone django-apps
hg pull django-static

とやると
「abort: repository is unrelated」と出てpullに失敗してしまいます。

hg pull -f django-static

とやればpull出来るので、2つのオリジンを持つリポジトリが出来上がります。
それぞれのdefaultのheadにdjango-apps-head,django-static-headというlocal tagを打って、
今後は随時移動していくことにしましょう。

同期をとる方法

merge

django-apps由来のheadとdjango-static由来のheadでmergeすることはできます。
これで成果の共有はできますが、もう二度と分離することができません。

revert

同期したいのは特定のディレクトリ(今回はstatic)だけなのでrevertを使うのもありです。

hg update django-apps-head
hg revert static/ -r django-static-head
hg commit -m "message"

とやればdjango-static-headの成果を持ってくることができます。
ただし、細かい履歴が消えてしまう、django-apps側に変更があっても上書きされてしまうなどの難点があります。

transplant

hg transplantは任意のchangesetを任意の位置に移植できます。
なのでサブセットの方から更新分のchangesetsを移植するのは簡単です。

hg pull django-static
hg update django-apps-head
hg transplant pullしてきた中で一番古いrevision番号:tip

とかやれば、簡単に同期できます。


後はdjango-appsにそのままpushしてもよし、
人に見せる用に適度にcommit圧縮してからpushするもよしです。
重要なのはstatic配下が同じ状態のそれぞれのrevisionがどこか記録しておくことです。
django-apps-head,django-static-headを適切に移動しておきましょう。


django-apps→django-staticの方向の同期はやや難しいです。
というのも、static配下の変更を含むchangesetがstatic配下以外への変更を含まないとは限らないからです。
Djangoの場合だとtemplates配下とセットで変更されていることが多いです。


例えばstatic/js/hoge.jsとtemplates/index.htmlが変更されているとして、
そのchangesetをdjango-staticの方にtransplantすると、
static/js/hoge.jsの差分は適用できますが、templates/index.htmlの差分を適用できずに、
transplantは中断してしまいます。
templates/index.htmlの適用できなかった差分はtemplates/index.html.rejとして保存されます。


本来のtransplantのフローでは適用できなかった差分を手動で適用し、
rejファイルを削除し、

hg transplant --continue

とやってtransplantを完了させます。


今回はstatic配下の変更以外は全く要らないので、こんな感じでいいでしょう。

hg transplant static配下の変更を含むrevision
find . -name "*.rej" | grep -v -P '\./static' | xargs rm 
hg transplant --continue

対象になるchangesetsを全部移植し終えたらlocal tagを移動した上で、
static配下が同一であるか確認しましょう。
ファイル内容が同一なだけなので、hg statusではダメです。

hg diff static/ -r django-apps-head:django-static-head

実際の運用

  1. django-apps(共同で使っているリポジトリ)から同期用リポジトリにpull
  2. django-static-headへtransplant
  3. django-static(個人で開発時に使っているリポジトリ)へpush
  4. django-staticでrebase
  5. django-staticから同期用リポジトリにpull
  6. django-apps-headへtransplant
    • (必要なら)transplantした分をcommit圧縮
  7. django-appsにpush