Gitを使ったOSS的開発フロー
Subversionを使ってる人は山ほどいると思いますが、
最近のOSS開発で使われているのが、
「分散リポジトリ」のGitやMercurialです
Ruby界隈だとGitHubあたりがベースになることが多いので、
GitHubのアカウントも作って、なんとなくGitだな・・・と思ってはいたのですが、
先日本屋でこの本を軽く読んで、「これはGitしかない・・・」と
- 作者: 濱野純(Junio C Hamano)
- 出版社/メーカー: 秀和システム
- 発売日: 2009/09/19
- メディア: 単行本
- 購入: 31人 クリック: 736回
- この商品を含むブログ (155件) を見る
たぶん、Git最大のポイントは、基礎設計こそLinus氏が行っているものの、
開発のトップが日本人であるってことです
その人が書いた本ですから、Gitに関してこれ以上の本はありません*1 *2
最大のポイントは、Gitの使い方について書かれているのではなく、
(OSSの)開発フローの様々なポイントで、
Gitをどう扱えばいいかが、丁寧に書かれていることです*3
というわけで相変わらず前置きが長くなりましたが、
私がRDGCの開発を行う際、どんな開発フローでGitを使っているか、を書いてみます*4
前提条件
RDGC 0.1 でのやりかた
- 自宅サーバにSubversion環境を置く
- 当然非公開
- 自宅のRedmineと連携
- 普段はそこと連携する環境Aで開発する
- SF.JPのリポジトリと連動している環境Bを別に用意
- 公開レベルに達したところで、環境AのコードをBにexportする
- 単純な更新・追加のみならこれでいい
- しかし、rename/deleteには手動で対処が必要
- 手動ということは、ミスがある
- 環境BからSF.JPにcommit
- SF.JPのsvnはせいぜい8回程度のcommitだが、自宅ではその10倍以上
- 普段は環境Aで開発しているが、持出し用の環境Cが存在
- SSH+リモートで環境Aで開発するようにはしている
- しかし、新幹線内など、回線はないけど時間はあるときにも進めたい
- 環境Aでの書きかけのコードをCに移したい場合がある
- 仕方ないので、いったんAのコードをcommitし、Cでupdateする
- 家に帰ったらこの逆
RDGC 0.2 でのやり方
環境
- リモート:master => SF.JPのリポジトリ/結果だけほしい・汚したくない
- ローカルA:master => remort:masterとの同期にのみ使用/完成したコードのみ
- ローカルA:[work branch] => 思いついた要素ごとにbranchを切る/好きにしていい
- ローカルB:[work branch] => Aの同名branchと同期
先ほどの本でも勧めていますが、
Gitはbranchを切るコストが安いというか、
ローカルbranchを切って開発するのが標準です
Subversionだと、branchを切るだけでリビジョンが進んでしまうので、
branchを切るという行為自体がリポジトリを汚してしまいます
(ちょっと何か試したいだけなのにね・・・(´・ω・`))
開発環境構築
git clone [remote] => リモートからコピー git checkout -b [work branch] => 作業用branchを切ってそっちで作業
Subversionでいうところのcheckoutです
Gitでのcheckoutは「branchを移動する」の意味です
「-b」をつけると、その名前のbranchを切って移動します
Gitでは同期用のmaster以外で作業をし、
最後にmasterにmergeするフローが基本なので、
常にどこのbranchにいるか意識するのは大事です*5
普段の作業
master以外のbranchであれば、好きにcommit/mergeを繰り返すことができます
先ほどの本では「やりたい仕事ごとにbranch」*6というのを勧めてますが、
RDGCの場合、現状で開発者は一人なので、branch一つでいろいろやってます
たぶん、開発者が増えたら変える必要があるかも
マージ
git checkout master => ローカル:masterに移動 git pull => リモート:masterの変更点を引っ張ってくる git checkout [work branch] => 一度作業場所に戻る git merge master => リモートからpullしたmasterの内容をmerge (edit..commit) => 競合したら修正する git checkout master => 再度、ローカル:masterに移動 git merge --squash --no-commit [work branch] => 作業の最終結果だけmerge => すでにworkにmasterの内容が含まれるから、失敗しないはず git commit => 最終結果をローカル:masterにcommit git push => リモート:masterを進める
ポイントがいくつかあります
- masterにmergeする前にpullする
- これはSubversionでも同じ
- work branch側にmasterをmergeする
- Gitは「祖先」のcommitしかmergeできない
- 言い換えると、merge先の内容を全部含んでないとmergeできない
- pushも同様
もう一つ、「公開リポジトリを汚さない」という条件を満たすのに必要なのが、
「git merge --squash --no-commit」です
通常、merge先のcommitを全て自分のツリーに結合してしまいます
ということは、試験的なゴミcommitまでmasterに結合されるので、
そのままpushすると、リモートのmasterにゴミができてしまいます
そこで「--squash」をつけると、
branchの「結果」だけをmasterにmergeできます
つまり、あたかも最初から迷わず修正を行っていたかのように見えます
Gitのリポジトリツリーを見るツール「gitk」(標準でついてます)で、
ここまでのフローを見るとこんな感じになるはずです
<work側>
※実際には「次の仕事」での処理を終えた後の画像
work branchでいろいろな作業をしたにもかかわらず、
masterにはそのcommitが表れていません
次の仕事
git checkout [work branch or work branch2] => 君は同じbranchに戻ってもいいし、新しいbranchを切ってもいい git merge master => masterの変更内容をマージ(同じbranchに戻った場合) edit..commit..edit..commit.. => 以下繰り返し
他の環境と同期する
GitはSubversionと違い、
管理情報は環境のトップにある「.git」のみしかありません
(各ディレクトリに「.svn」みたいなのは作られません)
そのため、環境を共有ディレクトリにし、
そこから「git clone [work branch]」とすれば、
それだけで環境をコピーできます
それでも、作業途中のコードをcommitしなければならないのは同じですが、
作業中のコードだけ他のbranchを切ってcommitし、
別環境は動作するものだけcloneすれば多少緩和されます*7
Gitを扱う時のポイント
最後に、ここまでで取り上げなかった細かいポイントを
- commitやmergeに失敗したらあせらず「git reset --hard HEAD^」
- 直前のcommitを「なかったこと」にする
- pushする前なら間に合うので、納得のいく状態になるまで試行錯誤可能
- 常にGUIでツリーを確認するとよい
- 先ほどのgitkでもいいし、TortoiseGitの「Git Show log」でも
- commitは細かい単位で行う
- 複数の内容を一度にcommitしない
- Gitは特定のcommitを削除したり、履歴を書き換えることができる
- この時、一つのcommitにいろいろ入っていると、手動の処理が発生してしまう
思ったよりだいぶ細かいことを書いてしまいましたが、
たぶん、実際に手を動かしてもらうと、
実はたいしたことではないってのがわかると思います
とはいえ、Gitの環境を持たない人の方が圧倒的に多いため、
RDGCではGitを使いつつも、Subversionにもcommitする方向で考えてます
(そこのmergeが手動になりますが、利用者の利便性を考えると・・・)
まあ、自分の開発環境に応じて、
SubversionとGit(やそれ以外の分散リポジトリ)を、
選択して使っていただければ(`・ω・´) b
*1:ただ、わりと抜けはありましたが 唐突に妙な単語が出てきて、索引にもなかったりとか
*2:トップが日本人でも、開発者に日本人が少ないためか、他に比べて日本語対応が甘いのはあります あと、出だしがLinuxのコード管理なので、Windowsとの相性もいまいち それでもWindowsで十分使えるレベルには達してますし、実際使ってます
*3:Gitには大量のコマンドが用意されていますが、実際に使うのはその一部だけで、そのコマンドを実装するためのサブコマンドが多いだけです [http://sourceforge.jp/magazine/09/03/16/0831212:title=SourceForge.JPのリファレンス]あたりがおすすめ
*4:社内でも使ってますが、所詮現在はプロトタイプの開発なので、わりとルーズな使い方なので参考にならない
*5:git branch コマンドを使いますが、EclipseのEGitや、TortoiseGitは作業branchをビジュアルに確認できるので楽です
*6:「トピックブランチ」という
*7:いったんコードを退避させる「git stash/stash pop」だとbranchを切る必要すらない