公開日:
Gitを使いこなしてチーム開発!【ブランチを使ったgitでのバージョン管理編】
この記事の目次(クリックで項目へジャンプします)
logo by git-scm
こんにちは。トゥイスクです。
突然ですが、みなさん、git使ってますでしょうか?
Gitとは、バージョン管理のためのシステムで、ウェブ制作とかシステム系会社の開発者の方なら、いまや聞いたことがない人はいないかもしれません。
今回は、そのgitについて、特に「チームで開発・運用をするために便利なgitの活用法」についてちゃんと整理してみたいと思います。
※この記事は、すでにgitをなんとなく使っていて、リポジトリの概念を理解している方におすすめです。「gitってなに?」「リポジトリとかpullとかpushとか、その辺が知りたいんじゃ」、という方は、このサイトが最初から丁寧に説明してくれているので、こちらを参照してみてください。
ブランチってなに?何故ブランチが必要なの?
ブランチを使っていないと、チーム開発でのバージョン管理が混乱状態に。。。
私自身、gitはバージョン管理としてずっと使っていましたが、一案件につき一人しか開発担当者がいない案件が多いので、すべてmasterブランチで管理していました。
もちろん、今後もずっと一人で担当していくのよ!という気概で居る方はそれでよいのですが、私の場合色々困ることがあったのです。
【困ったことその1:複数人での開発のとき、git最新版の管理がうまくできない】
・2人で同時に開発するときに、同ブランチで作業をすると、コンフリクト(後述)が起こりやすくなる。そして、同ブランチでコンフリクトが起こったらまあまあ面倒。
・masterブランチで、二人同時に修正を行っていると、結局最新版のmasterはどちらなのか、わからなくなる。
【困ったことその2:あとから見直して、どのコミットでどのファイル修正をしてるか、がうまく分かれていない】
・ほかの人がファイルを見たときに、「このコミットでは、結局どのファイルのどこが変わったの?」となって分かりにくい。
こういった困ったことはgitのブランチ機能が解決してくれます。
次から具体的にチームでのバージョン管理に便利な方法を紹介します。
Gitのブランチを活用した開発
いろいろなやり方があると思いますが、githubも推奨している、ブランチを切り分けてプルリクエストを使ってマージするやり方を紹介します。
今回はbitbucketでの説明となります。
目次
1. Bitbucket(またはgithub)でリモートリポジトリを作る(すでにない場合)
2. Bitbucket(またはgithub)でリモートリポジトリでブランチをつくる(すでにない場合)
3. ローカルリポジトリにブランチをfetchしてcheckout
4. ローカルリポジトリ内のブランチで作業
5. 作業が終わったらいつもどおりadd, commit
6. リモートリポジトリの該当ブランチにpush
7. Bitbucketで統合用のブランチにプルリクエスト
8. 統合用のブランチを管理する人が確認、OKならマージ
なるべくまとめるように頑張りますが、盛りだくさんになってしまいそうです。必要なところだけつまんでください。
1.Bitbucket(またはgithub)でリモートリポジトリを作ってローカルに反映(すでにない場合)
とりあえずリモートリポジトリを作ります。ツールとしてはbitbucketかgithubがおススメです。(詳しくは前述のサイトで見てください)
リポジトリがローカル(自分の開発環境内)にない場合はクローン(メニューの「クローン」の部分をコピーしてコマンドに張り付け)、すでにローカルリポジトリがある場合はpullで最新の状態に同期しましょう。
2.Bitbucket(またはgithub)でリモートリポジトリでブランチをつくる(すでにない場合)
Bitbucketであれば、リポジトリ内のメニュー「ブランチの作成」から作成できます。
ブランチの作成→ブランチ名をつける
今回は、ページごとにブランチを切り離して開発して、最終的にmasterに統合する、という設定でやってみます。
つくるブランチは’page_top’, ‘page_about’, ‘page_contact’の三種類とします。
【補足:ブランチの分け方について】
ブランチの分け方には、色々なやり方があるようですが、一般的には、「トピックブランチ」というやり方が主流のようです。
トピックブランチとは、例えば「このページを追加したい」とか、「バグを改修したい」といった、主旨に基づいてブランチを切り離すというもの。このやり方だと、ブランチごとの競合(あとで説明します)が起こりにくくなり、どこで何を直したかが分かりやすくなります。
切り離し方は会社のやり方を決めるのが良いかと思います。git-flowのしくみなど参考にするとよいかもしれません。(http://hm-solution.jp/lifehack/post2475.html)
3.ローカルリポジトリにブランチをfetchしてcheckout
ここらへんから、今回の本題です。
このままでは、リモートリポジトリ(bitbucket)上に作られたブランチが自分のローカルに反映されていません。
そこで、git fetchコマンドで、リモートにつくられたブランチ情報をローカルに同期します。
fetchした後は、現在の開発場所(この場合だとmaster)から、つくったブランチに移動する必要があります。その際にCheckoutコマンドを使います。
入力コマンド:
git fetch && git checkout page_about
Branch page_about set up to track remote branch page_about from origin. Switched to a new branch 'page_about'
コマンドプロンプトでこんな感じに帰ってきたらOK。今現在、ローカルリポジトリにpage_aboutのブランチが出来上がって、そこに移動してきた状態になります。
【補足:この辺で役に立つコマンド】
・現在のローカルのブランチ一覧を確認、自分がどこにいるかも確認(*がついているのが現在の場所)
git branch
・現在のローカルリポジトリとリモートリポジトリの一覧を確認
git branch -a
・ブランチの移動
git checkout 移動したいブランチ名
4.ローカルリポジトリ内のブランチで作業
ブランチに移動したら、そこで開発作業をします。
5.作業が終わったらいつもどおりadd, commit
開発作業が終わったら、addしてcommitします。これで、ローカルリポジトリのブランチ上での変更が完了しました。
コマンド(例):
git add *
(変更内容全てをadd)
git commit -m "page_aboutの追加"
(addしたものにコメントを付けてコミット)
6.リモートリポジトリの該当ブランチにpush
では、pushコマンドでこの変更をリモートにも反映させましょう。
コマンド:
git push origin リモートリポジトリのブランチ名
この場合は、リモートのpage_aboutブランチなので、git push origin page_aboutと打ちます。うまくいっていると、bitbucket上にコミットログが反映されています。
7.Bitbucketで統合用のブランチにプルリクエスト【開発者側】
ここまでで、ブランチ上での作業は終わりました。では、このブランチ上で開発した部分を、マスターに統合しましょう。
方法は、ローカルリポジトリのマスターでマージをしちゃって、それをorigin masterにpushするやり方もあるのですが、今回は、プルリクエストを活用する方法を紹介します。
【補足:プルリクエストのメリット】
・責任者がすべて開発の内容を把握できる
・確認してからマージをするため、コードレビューが出来る
bitbucket上でプルリクエストを作成します。
アクションメニューの「プルリクエストを作成」で、新しくプルリクエストを作成できます。開発をしたブランチから統合先に向けてプルリクエストをします。
この場合、page_aboutで行ったコミットの内容をmasterにマージしてほしいことを伝えます。
8.【管理者側】統合用のブランチを管理する人が確認、OKならマージ
プルリクエストの一覧は、NAVIGATIONメニューの「プルリクエスト」から見ることができます。画像では切れてしまいましたが、この下の部分で変更された内容の差分を見ることができます。内容がOKなら右上の「マージ」ボタンからマージします。
マージボタンを押すとpage_aboutのコミットされた部分と、もともとのmasterの差分がマージされ、masterへの統合完了です。
番外編:コンフリクト恐怖症を克服する
やったー!これでgitでブランチを切って、チームで同時に開発が出来る!
と思うかもしれませんが、実は、ここでもう一つ越えなければいけない壁があります。それが「コンフリクト(競合)」という現象です。
【コンフリクト(競合)とは】
仮にpage_aboutとpage_contactで、同時に同じファイルの修正を行っていたとします。
一度、page_aboutの修正は終わり、masterブランチにも統合済みです。しかし、同時に開発していたpage_contactのブランチには、masterの変更点は反映されていません。ここで、今までのとおりmasterにプルリクエストをしてマージしようとすると、「コンフリクト(競合)」という現象が起こります。
ちなみに、プルリクエストからマージしようとすると、Bitbucketの画面ではこんな感じにアラートっぽいものが出ます。
あまりよくわかっていなかったときは、これを見て「やってしまった…!!」とパニックになっていました。
でも、これって結構よくあることで、この現象が発生してしまっても慌てる必要はありません。
【コンフリクトの解決方法】
解決方法は2通りあります。
【1.masterでマージする】
これは、文字通りマージなので考え方は単純です。
手順:
1.作業用ブランチ(この場合page_contact)で作業後add,commit
2.git checkout master //ローカルリポジトリのmasterブランチに移動(masterが最新版なら省略)
3.git pull origin master //ローカルリポジトリのmasterブランチにリモートのmasterをプル(masterが最新版なら省略)
4.Git merge page_contact //page_contactの差分をマージ
5.コマンドプロンプトで
CONFLICT (content): Merge conflict in ファイル名
Automatic merge failed; fix conflicts and then commit the result
というコンフリクト発生のメッセージが出る
Masterブランチの該当ファイルを見ると、こんな感じになってる
6.手動でマージ(いらない部分を消す)
7.Masterブランチ上でadd,commitしてorigin/masterにpush
↓
統合完了!
【2.作業ブランチ上でリベースコマンドを使ってマージ】
一方、リベースは、履歴が一本になります。やっていることはちょっと複雑ですが、履歴がシンプルになるので、こちらの方がよいようなことも言われてます。
手順:
1.作業用ブランチ(この場合page_contact)で作業
2.git chack out master //ローカルリポジトリのmasterブランチに移動(masterが最新版なら省略)
3.git pull origin master //ローカルリポジトリのmasterブランチにリモートのmasterをプル(masterが最新版なら省略)
4.Git checkout page_contact//もう一回作業用のブランチに戻る
5.Git rebase master //マスターブランチをリベースする(リベースは、ファイルの変更部分を結合するコマンドです)
6.コマンドプロンプトで
CONFLICT (content): Merge conflict in ファイル名
error: Failed to merge in the changes
というコンフリクト発生のメッセージが出る
page_contactブランチの該当ファイルがこんな感じになっている
7.手動でマージ(いらない部分を消す)
8.作業ブランチ(page_contact)上でadd
9.リベースが終わったよ!というrebase –continueコマンドを打つ
git rebase --continue
10.commitしてorigin/master page_contactにpush
11.従来通りbitbucketからmasterにプルリクエスト
12.管理者がマージ
↓
統合完了!
こうやって書いてみると、「え?リベースのほうがめんどくさいんじゃないか?」という気がしてきますが、リベースを行うと、マージしたmasterの履歴は確かにキレイになりますし、プルリクエストも簡潔に済むので、こちらの方がよいのかなあ、と思います。
まとめ
長々と書いてしまいましたが、ついにまとめです。
・gitは機能ごとにトピックブランチを切って開発するとあとからわかりやすくて便利
・プルリクエスト機能を使えば「え?誰かいつの間に本番環境変更したの?ヒョエー!」現象を回避
・コンフリクトは怖くない。
Gitは、学習コストもあまりかからないので、ぜひ活用していきたいものです。