Subversionで攻めの開発を (いまさらだけど)

カテゴリ
ブックマーク数
このエントリーを含むはてなブックマーク はてなブックマーク - Subversionで攻めの開発を (いまさらだけど)
このエントリーをはてなブックマークに追加
こんにちは。ブログ担当のnabokov7です。

さてみなさん、ここのところ、livedoor Blog の新機能リリースのペースが上がっていることにお気づきでしょうか。

12月だけでこれだけの新規リリースのお知らせを出しました。
2007年12月27日 プライベートモードで記事を投稿できるようになりました
2007年12月25日 タグクラウド とタグ別ページを表示できるようになりました
2007年12月20日 カテゴリ別モブログ機能リリースのお知らせ
2007年12月18日 「話題のブログ」が新しくなりました
2007年12月18日 プレビュー機能強化と新リスログプラグインのお知らせ
2007年12月13日 投稿・編集を便利にするブックマークレットのご紹介
2007年12月11日 バリューコマースの商品をカンタンに紹介できるようになりました。
2007年12月11日 アップロードしたファイル一覧にサムネイルを表示しました
2007年12月10日 ブログ検索がさらに使いやすく!
2007年12月07日 ブログのページ移動(ナビゲーション機能)を強化しました
以前に比べてスピーディーなリリースが可能になった背景には、最近新しい仲間も増えてきたといった要因もあるのですが、もうひとつの大きな理由として、最近、開発を CVS から Subversion へ移行し、複数のブランチで複数の案件を平行して開発していくスタイルを確立できた、というのがあります。

いまさらサブバージョンかよ、という感はあるかと思いますが、ブログのプロジェクトは3年前からCVSベースで開発を続けてきており、14000以上のファイルがCVS管理下にあるのです。
また、本番化の方式として

・本番化専用のワーキングディレクトリで cvs update をかけて最新版にし、
・rsync で、新しくなったファイルだけを本番サーバに同期する (rsync --delete -e ssh -auvzC などを使った本番化用スクリプトがあります)

という手順をとっているため、

「全部同期するのは大変なので、必要なサブディレクトリ以下だけを rsync している。」
「CVS にコミットまではしたけど、もしかしたら本番サーバには rsync してないかもしれないファイルがある。」

といったことが長年積み重なり、とても気軽には移行に踏み切れない状態が続いていました。
しかし、開発担当者の数が増えてくると、

「別の人の作業がおわるまで全体が本番化できない」
「根元のライブラリを思い切って書き換えたいけど、他の作業への影響が大きすぎる」


などの問題が開発効率の足を引っ張るようになってきます。かといって、CVSでブランチを切って作業するのはなかなか面倒です。

そこで思い切って Subversion への移行を敢行したわけですが、その際のメモや、気付いた細かい点などを書き、年末の大掃除にかえたいと思います。

Subversion移行の準備



まず、移行作業の基本コンセプトとして

・現在本番機上できちんと動いているファイルセットのみを、新リポジトリへ import する。
・CVSにコミットしたまま本番化されていなかったファイルや、コミットさえされていないゴミファイルは新リポジトリには移行しない。 (あとで作業者各々が、旧ワーキングディレクトリから必要なファイルをサルベージしてきて新リポジトリへコミットしていくこと。)

というルールを決め、それに基づいて、以下のように作業をすすめました。

1. 現在のCVSのワーキングディレクトリをベースに、新リポジトリへのimport用ディレクトリを作成

まず、現在のCVSのワーキングディレクトリを別の場所に退避し、それをディレクトリまるごとコピーしてその上で作業をすすめます。

2. 全てのファイルが「実際に本番サーバで動作しているもの」であることを確認する

以下のようなコマンドラインを駆使して、実際の本番機にあるファイルと旧ワーキングディレクトリとの差分をとり、各ファイルの、いま現在本番稼働しているリビジョンを集めてきます。

↓ローカルのファイルと本番機上のファイルのdiffをとる
ssh (server) 'cat (remote_file)' | diff (local_file) -

↓あるローカルディレクトリ以下のファイルすべてのうち、本番サーバの方が古い、あるいは本番サーバにはないファイルのリストを作る。(rsync の --dry-run を使うのがミソ)
rsync --delete -e ssh -auvzC --dry-run (local_dir) (server):(remote_dir) | egrep -v '/$' | egrep -v '^(wrote|total|building)' > files.diff

etc.

3. ゴミファイルを消す

旧ワーキングディレクトリに残ったままになっている様々な一時ファイルを掃除します。

↓テンポラリファイル, バックアップファイルの削除
find . -name ".#*" | xargs rm
find . -name "*~" | xargs rm

etc.

.cvsignore や CVS/ ディレクトリなど、CVS専用のファイル群も同様にして削除します。
(.cvsignore については後の「6. 属性を整える」も参照)

4. 主にマカー対策

私もマカーですけど

・マカーの作業者がコミットしてしまいがちな ".DS_Store" などもこの機に忘れず削除しておきましょう。
・MacOSはファイル名の大文字と小文字を区別しないので、"foo.GIF" と "foo.gif" が両方あると後々ローカルでの作業時にはまります。両方存在するのはたいてい間違いなので、どちらか一方にまとめておきましょう。

5. きれいになったディレクトリを Subversion に import

履歴は必要になったときにCVS側を見ればいいので、心機一転、新プロジェクトとして import します。

6. 属性を整える

↓svn:executabe, svn:eol-style, svn:keywords ぐらいはまとめて propset しておく
find . -name "*.pm" | xargs svn propset svn:keywords Id
find . -name "*.pm" | xargs svn propset svn:eol-style native
find . -name "*.sh" | xargs svn propset svn:executable ON

etc.

↓ .cvsignore を使っていた場合は、その内容を svn:ignore 属性に反映させておく
(.cvsignore のあるすべてのディレクトリで以下を実行)
propset svn:ignore -F .cvsignore .

特にうちの場合、リポジトリ配下にあたる場所に var ディレクトリがあり、開発サーバではここにログやテンポラリファイルが書き出されています。
propset svn:ignore var .
して除外するなどしておかないと、間違って var 以下のファイルをコミットしてしまったり、開発サーバ上で別ブランチにスイッチするときにコンフリクトが起きたりしてかなりややこしいことになります。


subversion移行後の作業手順



移行後は、以下のような基本ルールを決めました。

・trunk は、いつ本番化されても大丈夫な状態というのが基本。
・すぐ本番に反映する手直し/緊急バグフィックス的なものは trunk で作業してもOKだが、それ以外の場合は必ずブランチを切ること。
・開発サーバで switch するときは、社内IRCで一声かける。作業がおわったら trunk に戻す。

※うちは開発サーバが一人一台ないので、開発サーバ上のワーキングディレクトリを自分のブランチに switch しては確認し、また trunk に戻す、という作業を日常的にすることになります。うちのチームでは、コーダやディレクタでも svn switch ぐらいは目をつぶっていてもできます。

・開発サーバ上で svn を root で実行しないこと。

※これもうちの開発環境独特の問題なのですが、開発者が皆 root でログインすることが多いため、そのままうっかり svn update とかされると更新されたファイルのパーミッションが全部 root になってしまって後始末が面倒です。

ブログの開発サーバでは、root の .bashrc に
alias svn='echo '\''*** svn should not normally be invoked by root. Check again and use /usr/bin/svn if you are really sure. ***'\'''
といった alias を仕込んであります。気持ち程度の策ですが。


その他、作業に便利な tips



↓自分のホームの ~/.subversion/config に以下を追加しておく。(新規にファイルを add するときに属性が勝手にセットされます。)
[miscellany]
enable-auto-props = yes

(中略)

[auto-props]
## images
*.png = svn:mime-type=image/png
*.jpg = svn:mime-type=image/jpeg
*.gif = svn:mime-type=image/gif
## executables
*.pl = svn:keywords=Id;svn:eol-style=native;svn:executable
*.sh = svn:keywords=Id;svn:eol-style=native;svn:executable
## source files
*.pm = svn:keywords=Id;svn:eol-style=native
*.sql = svn:keywords=Id;svn:eol-style=native
*.conf = svn:keywords=Id;svn:eol-style=native
*.txt = svn:eol-style=native
Makefile = svn:eol-style=native
## htmls
*.inc = svn:eol-style=native
*.html = svn:eol-style=native

・ ~/.tcshrc に
set blogrepos = 'http://(リポジトリのURL)'
を追加しておく。

(Macの場合は /Private/etc/bashrc に↓です)
blogrepos='http://(リポジトリのURL)'
こうすると、コマンドラインで $blogrepos とするだけでリポジトリのURLが指定できるので楽です。

ブランチでの普段の開発手順



以下、$blogrepos にリポジトリのURLがセットされているという前提で、ブランチでの開発手順を書いておきます。

1. (自分のローカル環境で) ブランチを作成してそこへスイッチする。
svn copy -m "(メッセージ)" $blogrepos/trunk $blogrepos/branches/(ブランチ名)

svn switch $blogrepos/branches/(ブランチ名)
※なお、ブランチやタグの命名規則については、こういった慣例等がありますので参考に。

2. ブランチで作業中、分岐以降に trunk で起きた変更点をブランチにマージする

(ブランチにswitch中のローカルディレクトリで)
svn merge --dry-run -r (分岐時点でのリビジョン番号):(trunkの最新リビジョン番号) $blogrepos/trunk
↑これで変更を確認し、↓これで実際に現在のワーキングディレクトリにマージする
svn merge -r (分岐時点でのリビジョン番号):(trunkの最新リビジョン番号) $blogrepos/trunk

問題なければそれをブランチへ commit
svn commit -m "merged from trunk ...(メッセージ)"

3. 動作確認のため開発サーバ上のディレクトリを作業ブランチへスイッチする

(開発サーバ上のワーキングディレクトリで)
svn switch $blogrepos/branches/(ブランチ名)

いまどのブランチにいるか分からなくなったときはもちろん
svn info

4. 動作確認できたら trunk へ merge

まずローカルのワーキングディレクトリを trunk に switch しておく。
svn switch $blogrepos/trunk
そこで
svn merge --dry-run -r (分岐時点でのリビジョン番号):(ブランチの最終リビジョン番号) $blogrepos/branches/(ブランチ名)
↑これで変更を確認し、↓これで実際にマージする
svn merge -r (分岐時点でのリビジョン番号):(ブランチの最終リビジョン番号) $blogrepos/branches/(ブランチ名)

コンフリクト等をすべて解消し、内容が確認できたら、trunk へ commit
svn commit -m "merged from branch...(メッセージ)"

5. そして trunk の動作が確認できたらリリースのタグをうつ
svn copy -m "(メッセージ)" $blogrepos/trunk $blogrepos/tags/(タグ名)

6. 本番化 (略)

7. いらなくなったブランチは適宜消す。
svn delete $blogrepos/branches/(ブランチ名)




いま気になっていること



svn switch が異常に重いです。スイッチ完了までにトイレに行って帰って来れる程時間がかかります。
さすがにファイルが一万以上もあるプロジェクトをワーキンディレクトリ丸ごとスイッチするのは、チェックだけでそれぐらいかかってしまうのでしょうか。それとも単に開発サーバが重いだけなのか... 忙しくてそのへんを検証する時間もない年末でした。
早々に、次は Git に移行だ、とかいった事態になるのでしょうか...


最後に



年末ぎりぎりにリリースされたブログのプライベート記事機能 ですが、実はもともとの予定には OpenID対応ははいっていませんでした。

実装もだいたい終わり、構成書のまとめやらhtmlコーディングの段階に入っていたある週末にふと、そうだ、OpenID に対応しよう、と思い立って実装し、週明けの月曜に

PG「こんな機能をつけたんですが」
ディレクター「じゃあそれでいきますか」


という感じで機能追加が決まりました。

他の会社ではなかなかこうはいかないと思います。素早い対応のできる (そして svn switch が理解できる) ディレクター他全チームメンバーに感謝致します。

レスポンス
コメント(1)
トラックバック(1)

このエントリーをはてなブックマークに追加