SourceTreeでgitブランチモデルの運用を試してみる

f:id:watass:20141020203524p:plain

前回の記事ではFuelPHPのバージョン管理をやりまして、ソースコード管理のモデルがとりあえずできたかなという感じです。ただ、gitのバージョン管理をどんなブランチモデルでやろうかなと考えていたところだったので、今回固めてきました。
gitは非常に奥が深いですね。まだ全然把握しきれてはいないと思いますが、とりあえず雰囲気はつかめたと思うので、今後こんな感じのブランチモデルで運用していこーって概要と、こんなケースにはこうやってSourceTreeを操作するよって内容を備忘録的にまとめておきます。

あとで対応できないケースが増えて、モデルの見直しが必要になることもあるかもしれませんが、今はこれでいく!ということで・・・


今後運用するブランチモデル

早速ですが、運用するブランチモデルについて概要を書いておきます。
基本的に個人開発なのでブランチ運用する必要性すらあるのかと思うかもしれませんが、今後誰かと開発をするケースを期待想定しつつ、masterブランチとdevelopブランチの二本で運用していきます。
ブランチ運用モデルの名ポスト、A successful Git branching modelではmasterブランチとdevelopブランチをメインブランチとして扱い、他に複数のトピックブランチを構える運用モデルを推奨していますが、個人開発ではやはり大げさすぎるので、トピックブランチを設けない形で運用することにします。
イメージ図はソースコード管理の図にあわせて以下に示すような感じです。

f:id:watass:20150106013421p:plain

ローカル、リモートリポジトリの両方でmaster、developブランチを保持します。開発はdevelopブランチで行い、本番環境(後々はテスト環境でやる)でも開発内容の適用はdevelopブランチに対してデプロイすることで実現します。
ある程度開発内容がまとまり、機能として十分に完成したらmasterブランチとマージします。リベースは行いません。マージもファストフォワードでは行わないようにします。理由はmasterブランチにコミットされた修正を全部後から確認できるようにするためです。
仮にmasterブランチにデプロイした内容で問題があったとしても、developブランチとのマージの履歴がしっかり見えていれば、以前のmasterブランチのバージョンに戻すことが容易になりますし、developブランチから継続して問題の修正ができるためです。そのため、masterブランチは常にdevelopブランチでテスト、確認ができた安定版のみをコミットすることがルールになります。

文面だけだと伝わりにくいと思いますので、この辺りの実例は簡単なデモを混じえてSourceTreeで試してみます。


開発環境について

ソースコード管理は以前アップした記事に倣いますので、githubを経由して、サーバとクライアントでgitを利用します。それぞれのバージョンは以下の通りです。

・サーバサイド
OS : Amazon Linux AMI 2014.09
PHP : version 5.3.29
FuelPHP : version 1.7.2
Git : version 2.1.0

・クライアントサイド
OS : Mac OS X Mavericks 10.10.1
Git : version 1.9.3
SourceTree : version 2.0.4

なお、ソースコード管理のモデルについては、以下の記事にまとめてありますので、参照していただければと思います。


developブランチの作成と変更内容のプッシュ

まずSourceTreeを起動し、git-flowボタンをクリックします。

f:id:watass:20150106014922p:plain

このように、ブランチの作成がここでできます。今回作成したいのはdevelopブランチなので、このままでOKです。もちろんブランチ名は変更することもできます。ブランチを作成すると、左メニューのブランチに作成したブランチが追加されます。developブランチをダブルクリックすると、developブランチにチェックアウトします。
developブランチに切り替えたら、プログラムを修正してコミットしてみましょう。前回作成したviewとなるトップページにリンクを追加します。

<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome! <?php echo $name; ?> !</h1>
<h3>My Blog</h3>
<a href="http://sil.hatenablog.com/">This is my blog.</a>
<h3>My Twitter</h3>
<a href="https://twitter.com/wata_sil/">This is my twitter account.</a>
<h3>My Github</h3>
<a href="https://github.com/wata727/">This is my Github account.</a>
</body>
</html>

修正を終えたら、いつものようにコミットしてプッシュします。ちょっと違うのは、コミット先がローカルのdevelopブランチで、プッシュ先もリモートのdevelopブランチだということですね。ちなみにSourceTreeの基本的な使い方は以下の記事で書いていますので、見てみてください。

プッシュを終えると、SourceTree上ではブランチはこんな感じで見えます。

f:id:watass:20150106015951p:plain

ブランチを作成してプッシュしているので、Github側でもdevelopブランチが作成されているのが確認できます。

f:id:watass:20150106020121p:plain

これでクライアント側のローカルリポジトリgithub上のリモートリポジトリにmasterブランチとdevelopブランチが作成できました。サーバ側のローカルリポジトリへのdevelopブランチはデプロイ時に作成しますので、次項で記載します。


ブランチ別に本番環境へデプロイ

github上のリポジトリにmasterブランチとdevelopブランチがありますので、それぞれのブランチ別に、本番環境のサーバへデプロイします。
まず、リモートリポジトリのdevelopブランチを元にサーバ上のローカルリポジトリにdevelopブランチを作成します。git checkoutコマンドで実現できます。

$ git checkout develop
M	composer.phar
Branch develop set up to track remote branch develop from origin.
Switched to a new branch 'develop'

これでブランチが作成されました。git branchコマンドで確認してみます。

$ git branch
* develop
  master

アスタリスクがついているのが現在のブランチです。これでdevelopブランチに切り替わっているのがわかりますね。git pullでdevelopブランチの変更内容を反映させましょう。

$ git pull origin develop
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 2), reused 6 (delta 2)
Unpacking objects: 100% (6/6), done.
From https://github.com/wata727/welcome
 * branch            develop    -> FETCH_HEAD
   bff1c8a..ae55ce6  develop    -> origin/develop
Updating bff1c8a..ae55ce6
Fast-forward
 fuel/app/views/login_view.php | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

これでブラウザから確認してみると・・・?

f:id:watass:20150106021127p:plain

反映されてますね。しかし、これは開発中の内容なので、すぐに以前のバージョンに戻せなくては困ります。もちろんできます。masterブランチにチェックアウトするだけです。

$ git checkout master

これでブラウザを更新すると・・・

f:id:watass:20150106021311p:plain

素晴らしい!git使ってて一番感動したかもしれません。
こんな感じで開発内容を適用しつつ、安定バージョンはいつでも出せるようになりました。


developブランチをmasterブランチにマージ

開発内容が十分にテスト完了し、本番環境に適用させたい!となったときには、developブランチをmasterブランチにマージさせます。前提にもあるように、履歴をしっかり残すためにノンファストフォワードマージを行います。
SourceTree上でmasterブランチに切り替え、マージボタンをクリックします。

f:id:watass:20150106232828p:plain

このように、マージするコミットを選択することができます。
今回はdevelopブランチの最新コミットをmasterブランチにマージしますので、developの最新コミットをクリックします。なお、ノンファストフォワードマージを実現するために、ファストフォワード可能でも新たなコミットを作成する、のチェックボックスにチェックを入れておきましょう。
これでOKすると、コミットされ、以下のような画面になります。

f:id:watass:20150106233513p:plain

これでブランチがマージされている様子がよくわかりますね。
後はいつもどおりプッシュして、サーバ側からプルしましょう。

$ git checkout master
M	composer.phar
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git pull origin master
remote: Counting objects: 1, done.
remote: Total 1 (delta 0), reused 1 (delta 0)
Unpacking objects: 100% (1/1), done.
From https://github.com/wata727/welcome
 * branch            master     -> FETCH_HEAD
   bff1c8a..2969143  master     -> origin/master
Updating bff1c8a..2969143
Fast-forward
 fuel/app/views/login_view.php | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

これでmasterブランチに開発内容の安定最新版を反映させることができます。
developブランチがトピックブランチの場合、マージした時点でブランチを破棄するのですが、今回の運用モデルでは開発内容は引き続きdevelopブランチに反映させていき、機能完成するごとに masterブランチにマージしていきます。


masterブランチのマージを取り消し

基本的にはこんな感じで運用していくのですが、実際にはそううまくいくことはなく、masterブランチに開発内容を適用してしばらく経ったあるとき、やっぱ前のバージョンに戻さなきゃまずい!という状態になったとします。
今回は適用したアカウントリストで、githubアカウントはやっぱり公開したくなかった!という設定で行います。実際にはこの程度の修正であれば、そのまま修正してプッシュするほうが早いのですが、実際の複雑なシステムでは、原因調査や、機能削除による影響確認などが必要になりますので、以前のアカウントリストが表示されないバージョンに戻すことが先決です。
masterブランチのマージを取り消すことで、masterブランチはアカウントリストが表示される前のバージョン、developブランチは以前の開発内容の続きから継続することができます。

SourceTreeでは現在、GUIでマージの取り消しができないらしいので、ターミナルを起動してコマンドを直打ちします。masterブランチに切り替え、ターミナルのボタンをクリックし、以下のコマンドを実行します。

$ git revert -m1 HEAD

ちなみに、これはマージ直後でなくては有効ではありません。その後に何度かコミットしている場合、HEADではなく、HEAD^だったり、HEAD^^だったりすると思いますので、その時々にあわせてください。
マージの取り消しはrevertでなくても、resetでもできますが、巻き戻しの履歴を残すためにrevertを使いましょう。完了するとSourceTree上では以下のようなブランチになります。

f:id:watass:20150106235442p:plain

これでmasterブランチをマージ前のコミットに戻すことができました。
このままプッシュして、本番環境でプルすればmasterブランチ、developブランチはそれぞれマージ前の状態に戻せます。素晴らしいですね。これがしっかりdevelopブランチとmasterブランチを分けて運用するメリットになるはずです。


developブランチを修正して再マージ

では、再度developブランチを修正しましょう。

<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome! <?php echo $name; ?> !</h1>
<h3>My Blog</h3>
<a href="http://sil.hatenablog.com/">This is my blog.</a>
<h3>My Twitter</h3>
<a href="https://twitter.com/wata_sil/">This is my twitter.</a>
</body>
</html>

修正した内容をdevelopブランチにコミット、プッシュします。

f:id:watass:20150107000606p:plain

サーバ側でdevelopブランチをプルしてくれば、適用内容が確認できます。とりあえずOKとなったら、再度masterブランチとマージします。手順は先ほどと同じです。

f:id:watass:20150107000857p:plain

ちなみに、このマージは競合が発生するので、SourceTreeさんに解決をお願いされますが、ほぼ指示に従うだけで大丈夫です。さっと直してコミットし、マージすれば上記のようなブランチになります。
これでプッシュし、サーバ側からmasterブランチをプルすれば・・・

f:id:watass:20150107001109p:plain

いいですね。もちろん、これでミスが見つかっても同じ手順で戻すことができますし、このままdevelopブランチに開発内容を継続的に反映させ続けることも可能です。


まとめ

  • ブランチモデルはmasterとdevelopの二本で運用
  • マージの履歴を残すためにリベースやファストフォワードマージは行わない
  • masterブランチは安定版のみをコミットする


次はデプロイの自動化ですね

gitでのブランチ運用モデルが固まったので、これで開発を進めていきたいところですが、開発の度にgit pullするのは面倒ですね。というわけで、次はデプロイの自動化など、CIを意識したプラットフォーム構築を行いたいと思います。AWSを駆使していきたいところですが、Codedeployなどはまだ東京リージョンで有効になっていないのが心残りですね。
AWSの最新リリース情報に気を配りつつ、現状のリソースでCIプラットフォームの構築を進めていきます。


参考にした記事

ブランチとは【ブランチ】 | サルでもわかるGit入門 〜バージョン管理を使いこなそう〜 | どこでもプロジェクト管理バックログ
# みんなだいすきおさるさんのgit講座。ブランチってなに?というレベルからよくわかります。
見えないチカラ: A successful Git branching model を翻訳しました
# ブランチ運用モデルの話で大変有名な記事の翻訳版です。ブランチ運用のイメージがつきます。
GitHub - SourceTreeでステージング用のブランチ作成 - Qiita
# SourceTreeでGithubリポジトリに対してブランチを作成する流れの参考にさせていただきました。
SourceTreeでGitHubを利用してみる(ブランチ関連) - yk5656 diary
# SourceTreeにおけるブランチへの操作諸々の参考にさせていただきました。
【git】分かりやすく!mergeは「合流」、rebaseは「付け替え」! | NullNote
# マージとリベースという特徴的な操作について、理解を深めることができました。
noanoa 日々の日記 : SourceTree と git のコマンドの取り消し操作の対応をまとめてみた
# マージの取り消しをSourceTreeでどうやるのか、という話が参考になりました。