Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
GitHub Flow (Japanese translation) Latest version is here: https://gist.github.com/Gab-km/3705015

GitHub Flow

31 Aug 2011

git-flowの問題点 (Issues with git-flow)

私は人々にGitを教えるためにあちこちを飛び回っているが、最近のほぼすべてのクラスやワークショップでgit-flowについてどう思うかを尋ねられた。私はいつも、git-flowは素晴らしいと思うと答えている。何百万ものワークフローを持ったシステム(Git)を提供し、ドキュメントもあるし、よくテストされている。フレキシブルなワークフローは、実に容易なやり方で多くの開発者の役に立つ。標準的なものになりつつあり、開発者はプロジェクトや企業の間を移動しつつこの標準的なワークフローに馴染むことができる。

しかしながら、それ故の問題も抱えている。新しいフィーチャーブランチをmasterではなくdevelopから開始するとか、hotfixesを扱う方法といったことを好まないような人たちから多くの意見を聞く。

私が考える大きな問題のひとつは、それが、ほとんどの開発者や開発チームが実際に必要とするよりも複雑すぎやしないか、ということだ。フローの遂行を支援するために開発された巨大なヘルパースクリプトであり、あまりに複雑すぎる。

クールかもしれないが、GitのGUIツールには強制することができず、コマンドラインでしか使えないという問題がある。すべての手順を手動で行う必要もある。そのための複雑なワークフローをしっかりと学ばなければならない人たちが、コマンドラインでの作業に不慣れな人たちとイコールでもある。これは大きな問題点だ。

これらの問題点は、手順をもっとシンプルにするだけで容易に解決できる。GitHubでは、git-flowを使っていない。私たちが使う手順、いつも使っている手順はとてもシンプルなGitワークフローだ。

そのシンプルさには多くのメリットがある。ひとつは、簡単に理解できるということ。より素早く作業ができ、何かを台無しにしてしまうとか間違ってしまった手順をやり直すといったこともめったに起こらない。他にも、プロセスを支援するためのラッパースクリプトが必要ないため、GUIプログラムも問題なく使えるというメリットもある。

GitHub Flow

さて、なぜGitHubではgit-flowを使わないのだろうか? 私たちが常にデプロイをするから、というのが主な理由ではある。 git-flowのプロセスは主として「リリース」を中心に設計されている。 私たちはプロダクション環境へのデプロイを毎日(たいていは日に何回も)行うため、「リリース」というものがない。 私たちはチャットルーム内のロボットを通じてデプロイをすることができ、そこにはCIの結果も表示される。 私たちはテストとデプロイの手順を可能な限りシンプルにするようにしており、それらをすべての従業員が安心して行うことができる。

定期的にデプロイを行うことにはいくつかの利点がある。 数時間毎にデプロイをすれば、大きなバグが沢山入るようなことはほぼありえない。 小さなバグが入ることはあるだろうが、そういったものは素早く修正して再デプロイすることができる。 本来なら「hotfix」ブランチや普段の手順とは違う形で修正を行おうとするだろうが、私たちの場合はそれも通常のプロセスの一貫でしかない。GitHubのやり方では、hotfixと小さな機能追加とに違いはまったくない。

四六時中デプロイすることのもうひとつの利点は、あらゆる種類の問題を迅速に解決することが可能になる点だ。 私たちは、セキュリティ上の問題や、小さいけれども重要な機能の要望にとても迅速に対応することができる。 そして、それらの変更に対処する際は、普段の開発や大きな機能の開発をする際に使うのとまったく同じプロセスを使うことができる。

すべてが同じプロセスであり、すべてがとてもシンプルだ。

どうやっているのか

GitHub Flowとは何だろうか?

  • masterブランチのものは何であれデプロイ可能である
  • 新しい何かに取り組む際は、説明的な名前のブランチをmasterから作成する(例: new-oauth2-scopes
  • 作成したブランチにローカルでコミットし、サーバー上の同じ名前のブランチにも定期的に作業内容をpushする
  • フィードバックや助言が欲しい時、ブランチをマージしてもよいと思ったときは、プルリクエストを作成する
  • 他の誰かがレビューをして機能にOKを出してくれたら、あなたはコードをmasterへマージすることができる
  • マージをしてmasterへpushしたら、直ちにデプロイをする

これがフローのすべてだ。 とてもシンプルかつ効率的で、かなり大きなチームでも機能する。現在GitHubは35人で、そのうちの約15〜20人が一度に同じプロジェクト(github.com)で作業している(訳注:数字は2011年8月時点のもの)。 ほとんどの開発チーム(同時期に同じコードで作業をし、コンフリクトを発生させる可能性のある集団)はこれくらいか、もっと小さいと思う。 とりわけ、迅速に一貫したデプロイを行なうような進歩的なチームなら。

では、各ステップを順に見て行こう。

#1 - masterブランチのものは何であれデプロイ可能である

このシステムにおいて困難なルールは、おおむねこの点だけである。 明確に一貫した目的をもつ唯一のブランチがあり、それをmasterと呼ぶ。 それは、そのブランチが既にデプロイされているか、または最悪の場合でも数時間以内にはデプロイされる、ということを意味する。 ブランチが巻き戻される(作業内容を取り消すためにブランチが古いコミットを指すようにする)ことは非常に稀である − もし問題が起きたら、コミットは取り消されるか(reverted)、問題を修正した新しいコミットが行われるが、ブランチ自身がロールバックすることはほとんどない。

masterブランチは安定しており、常に、そう常にデプロイ可能かつそこから新しいブランチを作成できる状態になっている。 テストされていなかったり、ビルドを破壊するようなコードをmasterにpushした場合には、開発チーム間におけるソーシャルな取り決めを破ることになり、ちょっと気まずい思いをすることになる。 我々がpushしたすべてのブランチではテストが実行され、その結果がチャットルームに報告される。もしテストを手元で実行していない場合には、サーバー上のトピックブランチ(たいていは1つのコミットだけのブランチ)にpushして、Jenkinsがその結果を教えてくれるのを待つこともできる。

デプロイを行った時だけ更新されるdeployedブランチを用意することもできるが、我々はそのようなことはしない。 我々は、現在デプロイされているSHA(ハッシュ)をWebアプリ経由で公開するようにし、比較が必要な場合はそれを単にcurlするだけにしている。

#2 - masterから説明的なブランチを作成する

何か作業を始めたい時は、安定したmasterブランチから説明的な名前のブランチを作成する。 GitHubの今のコードでは、user-content-cache-keysubmodules-init-taskredis2-transitionといった感じだ。 このやり方にはいくつか利点がある。 fetchすると他の皆が現在作業しているトピックを知ることができる、というのが1つ。 しばらくの間ブランチを放っておいて後からその作業に戻った時に、何をしていたかすぐに思い出せるという利点もある。

GitHubのブランチリストページでは、最近どんなブランチで作業がされているのか、どれくらいの作業をしているのかを大まかに知ることができるので、その点でも素晴らしい。

github branch list

これは、もうすぐ実装される機能の一覧におおまかな現在の状況が付いているようなものだ。このページはとても素晴らしい − 現在選択しているブランチと比較して、それぞれのブランチがどのような固有の作業内容を含んでいるかだけが表示され、最も最近作業されたものが一番上に来る。興味を惹かれれば、Compareボタンをクリックして実際の差分を見たり、そのブランチ固有のコミット一覧を見ることもできる。

この文章を書いている時点では、我々のリポジトリにはまだマージされていない作業を含む44のブランチがあり、そのうち先週pushされたものが9個から10個ほどあることもわかる。

#3 - 名前をつけたブランチに定期的にpushする

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のブランチリストページを見るよう、全員が動くことにも繋がる。

#4 - いつでもプルリクエストを作る

GitHub has an amazing code review system called Pull Requests that I fear not enough people know about. Many people use it for open source work - fork a project, update the project, send a pull request to the maintainer. However, it can also easily be used as an internal code review system, which is what we do.

Actually, we use it more as a branch conversation view more than a pull request. You can send pull requests from one branch to another in a single project (public or private) in GitHub, so you can use them to say “I need help or review on this” in addition to “Please merge this in”.

early pr message

Here you can see Josh cc’ing Brian for review and Brian coming in with some advice on one of the lines of code. Further down we can see Josh acknowledging Brian’s concerns and pushing more code to address them.

more discussion

Finally you can see that we’re still in the trial phase - this is not a deployment ready branch yet, we use the Pull Requests to review the code long before we actually want to merge it into master for deployment.

If you are stuck in the progress of your feature or branch and need help or advice, or if you are a developer and need a designer to review your work (or vice versa), or even if you have little or no code but some screenshot comps or general ideas, you open a pull request. You can cc people in the GitHub system by adding in a @username, so if you want the review or feedback of specific people, you simply cc them in the PR message (as you saw Josh do above).

This is cool because the Pull Request feature let’s you comment on individual lines in the unified diff, on single commits or on the pull request itself and pulls everything inline to a single conversation view. It also let you continue to push to the branch, so if someone comments that you forgot to do something or there is a bug in the code, you can fix it and push to the branch, GitHub will show the new commits in the conversation view and you can keep iterating on a branch like that.

If the branch has been open for too long and you feel it’s getting out of sync with the master branch, you can merge master into your topic branch and keep going. You can easily see in the pull request discussion or commit list when the branch was last brought up to date with the master.

master merge

When everything is really and truly done on the branch and you feel it’s ready to deploy, you can move on to the next step.

#5 - マージはプルリクエストがレビューされた後だけ

We don’t simply do work directly on master or work on a topic branch and merge it in when we think it’s done - we try to get signoff from someone else in the company. This is generally a +1 or emoji or “:shipit:” comment, but we try to get someone else to look at it.

shipit comment

Once we get that, and the branch passes CI, we can merge it into master for deployment, which will automatically close the Pull Request when we push it.

#6 - レビューのあとは直ちにデプロイする

Finally, your work is done and merged into the master branch. This means that even if you don’t deploy it now, people will base new work off of it and the next deploy, which will likely happen in a few hours, will push it out. So since you really don’t want someone else to push something that you wrote that breaks things, people tend to make sure that it really is stable when it’s merged and people also tend to push their own changes.

Our campfire bot, hubot, can do deployments for any of the employees, so a simple:

hubot depoy github to production

will deploy the code and zero-downtime restart all the necessary processes. You can see how common this is at GitHub:

our campfire logs

You can see 6 different people (including a support guy and a designer) deploying about 24 times in one day.

I have done this for branches with one commit containing a one line change. The process is simple, straightforward, scalable and powerful. You can do it with feature branches with 50 commits on them that took 2 weeks, or 1 commit that took 10 minutes. It is such a simple and frictionless process that you are not annoyed that you have to do it even for 1 commit, which means people rarely try to skip or bypass the process unless the change is so small or insignificant that it just doesn’t matter.

This is an incredibly simple and powerful process. I think most people would agree that GitHub has a very stable platform, that issues are addressed quickly if they ever come up at all, and that new features are introduced at a rapid pace. There is no compromise of quality or stability so that we can get more speed or simplicity or less process.

まとめ

Git itself is fairly complex to understand, making the workflow that you use with it more complex than necessary is simply adding more mental overhead to everybody’s day. I would always advocate using the simplest possible system that will work for your team and doing so until it doesn’t work anymore and then adding complexity only as absolutely needed.

For teams that have to do formal releases on a longer term interval (a few weeks to a few months between releases), and be able to do hot-fixes and maintenance branches and other things that arise from shipping so infrequently, git-flow makes sense and I would highly advocate it’s use.

For teams that have set up a culture of shipping, who push to production every day, who are constantly testing and deploying, I would advocate picking something simpler like GitHub Flow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment