Scott Chacon on the Interwebs 31 Aug 2011
master
ブランチのものは何であれデプロイ可能である- 新しい何かに取り組む際は、説明的な名前のブランチをmasterから作成する(例:
new-oauth2-scopes
) - 作成したブランチにローカルでコミットし、サーバー上の同じ名前のブランチにも定期的に作業内容をpushする
- フィードバックや助言が欲しい時、ブランチをマージしてもよいと思ったときは、プルリクエストを作成する
- 他の誰かがレビューをして機能にOKを出してくれたら、あなたはコードを
master
へマージすることができる - マージをして
master
へpushしたら、直ちにデプロイをする
これがフローのすべてだ。 とてもシンプルかつ効率的で、かなり大きなチームでも機能する。現在GitHubは35人で、そのうちの約15〜20人が一度に同じプロジェクト(github.com)で作業している(訳注:数字は2011年8月時点のもの)。 ほとんどの開発チームはこれくらいか、もっと小さいと思う。
では、各ステップを順に見て行こう。
このフローで困難なルールは、この点だけである。デプロイ用のブランチをmaster
と呼ぶ。
master
は、既にデプロイされているか、または最悪の場合でも数時間以内にはデプロイされる。
ブランチが巻き戻される(作業内容を取り消すためにブランチが古いコミットを指すようにする)ことは非常に稀である − もし問題が起きたら、コミットは取り消されるか(reverted)、問題を修正した新しいコミットが行われるが、ブランチ自身がロールバックすることはほとんどない。
master
ブランチは安定しており、常に、そう常にデプロイ可能かつそこから新しいブランチを作成できる状態になっている。
テストされていなかったり、ビルドを破壊するようなコードをmaster
にpushした場合には、開発チーム間におけるソーシャルな取り決めを破ることになり、非難をまぬがれないだろう。。
我々がpushしたすべてのブランチではテストが実行され、その結果がチャットルームに報告される。もしテストを手元で実行していない場合には、サーバー上のトピックブランチ(たいていは1つのコミットだけのブランチ)にpushして、Jenkinsがその結果を教えてくれるのを待つこともできる。
我々は、現在デプロイされているSHA(ハッシュ)をWeb経由で公開し、比較が必要な場合はそれを単にcurlで取得する。
何か作業を始めたい時は、安定したmaster
ブランチから説明的な名前のブランチを作成する。
GitHubの今のコードでは、user-content-cache-key
やsubmodules-init-task
、redis2-transition
といった感じだ。
このやり方にはいくつか利点がある。
fetchすると他の皆が現在作業しているトピックを知ることができる、というのが1つ。
しばらくの間ブランチを放っておいて後からその作業に戻った時に、何をしていたかすぐに思い出せるという利点もある。
GitHubのブランチリストページでは、最近どんなブランチで作業がされているのか、どれくらいの作業をしているのかを大まかに知ることができるので、その点でも素晴らしい。
これは、もうすぐ実装される機能の一覧におおまかな現在の状況が付いているようなものだ。このページはとても素晴らしい − 現在選択しているブランチと比較して、それぞれのブランチがどのような固有の作業内容を含んでいるかだけが表示され、最も最近作業されたものが一番上に来る。興味を惹かれれば、Compareボタンをクリックして実際の差分を見たり、そのブランチ固有のコミット一覧を見ることもできる。
この文章を書いている時点では、我々のリポジトリにはまだマージされていない作業を含む44のブランチがあり、そのうち先週pushされたものが9個から10個ほどあることもわかる。
git-flowとの大きな違いのひとつが、名前を付けたブランチを定期的にサーバーにpushするという点だ。我々がデプロイの観点で本当に気にしているものはmaster
だけなので、サーバーへpushすることが誰かの手を煩わせたり、混乱を引き起こしたりすることはない − master
以外のものはすべて、単に作業中の何かだということに過ぎない。
それによって、ノートパソコンを紛失したりハードディスクが故障した場合でも作業内容が常にバックアップされていることも確実となる。より重要なこととして、皆が定期的にコミュニケーションをとるようになる。単なるgit fetch
が、皆が作業していることについてのTODOリストを与えてくれる。
$ git fetch
remote: Counting objects: 3032, done.
remote: Compressing objects: 100% (947/947), done.
remote: Total 2672 (delta 1993), reused 2328 (delta 1689)
Receiving objects: 100% (2672/2672), 16.45 MiB | 1.04 MiB/s, done.
Resolving deltas: 100% (1993/1993), completed with 213 local objects.
From github.com:github/github
* [new branch] charlock-linguist -> origin/charlock-linguist
* [new branch] enterprise-non-config -> origin/enterprise-non-config
* [new branch] fi-signup -> origin/fi-signup
2647a42..4d6d2c2 git-http-server -> origin/git-http-server
* [new branch] knyle-style-commits -> origin/knyle-style-commits
157d2b0..d33e00d master -> origin/master
* [new branch] menu-behavior-act-i -> origin/menu-behavior-act-i
ea1c5e2..dfd315a no-inline-js-config -> origin/no-inline-js-config
* [new branch] svg-tests -> origin/svg-tests
87bb870..9da23f3 view-modes -> origin/view-modes
* [new branch] wild-renaming -> origin/wild-renaming
さらにそれによって、他の皆が何をしているのかを知ったり、助けを必要としていないかを確認するためにGitHubのブランチリストページを見るよう、全員が動くことにも繋がる。
GitHubには、残念だが十分な人々には知られていない Pull Requests と呼ばれる素晴らしいコードレビューの仕組みがある。多くの人々はオープンソースでの活動 ― プロジェクトをフォークする、プロジェクトを更新する、メンテナーにプルリクエストを送る ― にそれを使っている。しかし、プルリクエストは内部コードレビューの仕組みとして簡単に利用することもできて、我々はそうしている。
実際、我々はプルリクエストよりもブランチでの会話ビューとしてもっとPull Requestsを使っている。GitHub上の1つのプロジェクト(パブリックまたはプライベート)において、あるブランチから他のブランチへプルリクエストを送ることができるので、「これをマージしてほしい」に加えて「これに助けやレビューを必要としているんだ」と言うのにプルリクエストを使うことができる。
JoshがBrianにレビューのためにCCして、Brianが何行かあるコードの1行へのアドバイスと共にコメントしたのが分かるだろう。さらにその下ではJoshがBrianの懸念に同意して、それらに取り組むためより多くのコードをプッシュしたことが分かる。
結局、我々はまだ試行フェーズ ― これはまだデプロイの準備ができたブランチではないということ ― におり、我々は実際にデプロイのために master
にマージしたいと思うよりずっと前からコードをレビューするためにPull Requestsを使っている。
もしあなたが機能やブランチの進捗で嵌っていて助けやアドバイスが必要なら、またはもしあなたが開発者であなたの作業のレビューをしてくれるデザイナーが必要なら、あるいはたとえあなたがほとんどまたは全くコードを持っていないがスクリーンショットや一般的なアイディアがあるなら、プルリクエストをオープンするのだ。GitHubのシステム上で @ユーザ名 を追加することで人々をccすることができるので、もし特定の人のレビューやフィードバックが欲しいなら、(上でJoshがやったのを見たように)プルリクエスト・メッセージ内で単純に彼らにccすればいいのだ。
プルリクエストの機能によりunified diffや1コミット、またはプルリクエスト自体の各行にコメントを入れられて、インラインの全てを1つの会話ビューに持ってこられるので、これはクールだ。それはまたブランチにプッシュし続けられるので、もしあなたが何かをやり忘れたりコードにバグがあると誰かがコメントすれば、あなたはそれを修正してブランチにプッシュし、GitHubが会話ビューに新しいコミットを表示して、こんな風にブランチに繰り返していられるのだ。
もしブランチがあまりに長くオープンになっていて、 master
ブランチと同期しないようになってきたと感じたら、あなたのトピック・ブランチを master
にマージして進み続けよう。ブランチが master
に最後に更新したのがいつか、プルリクエストの議論やコミットリストで簡単に分かる。
ブランチですべてが本当に完了し、もうデプロイしてもいい頃だと感じた時、次のステップに進むことができる。
我々は単純に master
で直接作業したり、トピック・ブランチで作業して完了したと思ったときにマージしたりはしない ― 我々は会社にいる他の誰かに締めくくってもらおうとする。これは一般に +1 や絵文字、 ":shipit:
" コメントであるが、我々は他の誰かにこれを見てもらうようにするのだ。
一度我々がこれをキメ、ブランチがCIをパスすると、我々はデプロイのためにこれをmasterにマージすることができ、それをプッシュしたときに自動的にプルリクエストをクローズする。
最終的に、あなたの作業は完了しmasterブランチにマージされる。これは、たとえあなたが今デプロイしなくとも、これを基に人々が新しい作業のベースにして、新しいデプロイが、これは数時間のうちに起こりそうであるが、押し出される。よって他の誰かにあなたの書いたものが壊してしまうような何かを本当にプッシュしてほしくないので、マージされた時には人々はそれが本当に安定していることを確かめたくなるし、彼らの変更をプッシュしたくなる。
我々のcampfire bot、hubotは、従業員の何でもをデプロイできるので、簡単な:
hubot depoy github to production
がコードをデプロイし、ダウンタイムなしで必要なすべてのプロセスをリスタートする。これがGitHubでどれだけありふれたものか分かる:
1日に約24時間、6人の異なる人々(サポート担当やデザイナーを含む)がデプロイしていることが分かるだろう。
私はこれを、1行の変更を含む1つのコミットでもって複数のブランチに行ったことがある。プロセスはシンプルで一本道、拡張性があって力強い。あなたはそれを、フィーチャー・ブランチに2週間かかる50コミットでやることも、10分かかる1コミットでやることもできる。こんなにも単純で摩擦の無いプロセスなので、1コミットでさえ、これは変更がとても小さかったり大したことがないため問題にならない限りは、人々がめったにプロセスをスキップしたり迂回したりしようとしないことを意味するが、それをしなければならないか悩まなくてよい。
これは信じられないほど簡単でパワフルなプロセスだ。GitHubがとても安定したプラットフォームを持ち、もしイシューが起票されたならそれらは速やかに対処され、新しい機能は迅速なペースで導入されるということに、ほとんどの人々が同意してくれるものと考えている。我々はさらなるスピードや単純さ、より少ないプロセスが得られるように、品質や安定性への妥協がない。
git-flowは素晴らしいと思う。ドキュメントもあるし、よくテストされている。 しかし問題もある。 新しいフィーチャーブランチをmasterではなくdevelopから開始するとか、hotfixブランチを使うのを好まないような人たちもいる。
問題のひとつは、複雑すぎやしないか、ということだ。 GUIツールには強制することができず、コマンドラインでしか使えない。 そのための複雑なワークフローをメンバーがしっかりと学ばなければならない。中にはコマンドラインに不慣れな人たちもいる。 これは大きな問題点だ。
これらの問題点は、手順をもっとシンプルにすれば容易に解決できる。 GitHubでは、git-flowを使っていない。私たちが使っているのはとてもシンプルなGitワークフローだ。
シンプルさには多くのメリットがある。 ひとつは、簡単に理解できるということ。より素早く作業ができる。 またラッパースクリプトが必要ないため、GUIでも問題なく使える。
なぜGitHubではgit-flowを使わないのだろうか? 私たちが常にデプロイをするから、である。 git-flowのプロセスは主として「リリース」を中心に設計されている。 私たちは本番環境へのデプロイを毎日(日に何回も)行うため、「リリース」というものがない。 チャットルームのロボットを通じてデプロイをすることができ、そこにはCIの結果も表示される。 テストとデプロイの手順を可能な限りシンプルにするようにしており、それらをすべての従業員が安心して行うことができる。
定期的にデプロイを行うことにはいくつかの利点がある。 数時間毎にデプロイをすれば、大きなバグが沢山入るようなことはほぼありえない。 小さなバグが入ることはあるだろうが、そういったものは素早く修正して再デプロイすることができる。 本来なら「hotfix」ブランチや普段の手順とは違う形で修正を行おうとするだろうが、私たちの場合はそれも通常のプロセスの一貫でしかない。GitHubのやり方では、hotfixと小さな機能追加とに違いはまったくない。
四六時中デプロイすることのもうひとつの利点は、あらゆる種類の問題を迅速に解決することが可能になる点だ。 小さなバグフィクスでも、大きな機能の開発でも、まったく同じプロセスで行われる。
すべてがとてもシンプルだ。
Git自体は理解するのにかなり複雑である。 つまりGitを必要以上に複雑に使うワークフローを作成することは、メンバーの精神的な苦労を増やすことになる。 あなたのチームに合うもっとも単純なシステムを使うこと、そして絶対に必要になったときにのみ複雑さを入れることを推奨する。
製品を毎日プッシュしテストしデプロイするというリリースの文化を作り上げてきたチームに対して、私はGitHub Flowのようなシンプルフローをお勧めする。