#12 チームでgitを使い始めてよかった!

こんばんわ、1年ぶりの投稿になります。せい(@shin1rosei)です。 キライな言葉は「面白法人なんだから面白いことしろよ」と言われることです。 自分は真面目一本で生きてきて大して面白い人間ではないので辛くなります。

このエントリはtech.kayac.com Advent Calendar 2012 12日目の記事になります.

テーマは「私の中のマイイノベーション2012」ということで、 今年を色々振り返ってみってみて、かなり地味な内容になりますが、一番効果が高かったなーと感じる「チームでgitを使い始めたこと」をお話したいと思います。

使い始めるまで

今まで自分が関わっていたプロジェクトは(小学生と言われるの覚悟で)subersionを使うのが一般的で、 gitの恩恵にあやかりたいプログラマは"git-svn"を使っていました。

ただ、次のような問題点がありました。

  • projectが巨大になるとgit svnが重すぎてツライ
  • svn switchが満足に扱えるいいGUIアプリがないため、プログラマー以外branchの切り替えができず、他職種は都度checkoutを強いられてツライ
  • @typesterにdisられてチームのモチベがダウンしてツライ

そこで、gitを本格的にチームで運用することを決定しました。

結果的に見て一番大変だったのは「他職種の制作陣の開発環境にgitの環境を整える」ことでした。制作陣の各環境にgitの環境を整えるのですが、ターミナルもあまり触ったことがないという人がほとんどなので、鍵の生成から、gitのツールの利用方法までをレクチャーしました。

なかには(さっき鍵作ったばかりなのに)「パスフレーズ忘れちゃったんですけど」みたいなことを言われちゃったりもしますが、そこを笑って許してあげる度量が必要です(自分にはその度量はありませんでした)。

gitのbranchの切り替えやpull, push, commitの理解などは最近は下記のとてもわかりやすいスライドもあったりして、自分の想定よりもスムーズに導入できたなと感じております。

こわくないgit

利用しているツール

SourceTree

基本的にプログラマー陣はコマンドラインのgitを使っていますが、それ以外の職種はほぼSourceTreeを使っています。

gitの導入を決めたのも、このツールの完成度が高く、しかも無料(ユーザ登録は必要)で使えたためと言っても過言ではありません。 Macのsubersionクライアントにありがちなsvn switchできなかったり挙動が不安定だったりということもありません。

tig

ターミナル上でもうちょっとカジュアルにgitのlogやdiffを確認したいというときはtigを使っています。

デプロイ用のサーバにもインストールしておくと現在本番反映されている内容が瞬時に確認できるので重宝してます。

コンソールから使える git ブラウザ、tig が超便利

IRCとの連携

弊社では一昨年くらいからIRC熱が徐々に高まって、IRCでの情報共有を活発化しようという動きがあります。

現在のプロジェクトでは主だったところでは下記の2つをIRCで共有してます。

  • gitへのpush
  • 本番環境へのデプロイ

基本的にはどちらも弊社で運用しているircに投稿するnopasteへそれぞれPOSTしてるというシンプルなものです。IRCを利用していなくてもメールなどでこのような情報が流れると情報共有がスムーズにできて素晴らしいですね。

gitへのpushはgitのpost-receiveで下記のスクリプトを実行するようにしてます。

#!/bin/sh

export LANG=ja_JP.UTF-8

# IRC channnel
CHANNEL="#channel"

read IN

OLD=`echo ${IN} | cut -d ' ' -f 1`
NEW=`echo ${IN} | cut -d ' ' -f 2`
REF=`echo ${IN} | cut -d ' ' -f 3`

git rev-list $NEW ^$OLD --reverse | while read COMMITID
do
    MSG=`git --no-pager log -1 --format='%an committed "%s"' $COMMITID`
    DIFF=`git show $COMMITID`

    curl --data-urlencode "summary=${MSG}:${REF}" --data-urlencode "text=${DIFF}" --data-urlencode "channel=${CHANNEL}" --data "notice=1" http://xxxx.kayac.com/nopaste
done

出力例

commit 85b8dcd18c703f156a7408dd17e23529e52189aa
Author: dummy user %lt;dummy-user@kayac.com%gt;
Date:   Wed Dec 12 10:17:57 2012 +0900

    count access num of quiz link

diff --git a/root/tmpl/common/footer.mt b/root/tmpl/common/footer.mt
index 5bff66d..691be9e 100644
--- a/root/tmpl/common/footer.mt
+++ b/root/tmpl/common/footer.mt
@@ -18,7 +18,7 @@
 %lt;nav id="js-embed-content"%gt;
     %lt;!--%lt;h1 class="name"%gt;MENU%lt;/h1%gt;--%gt;
 ? if (models('Schema::Event')-%gt;current) {
-    %lt;div class="specialBnr"%gt;%lt;a href="%lt;?= link_for('/special_practice_event') ?%gt;" onclick="javascript:_gaq.push(['_trackPageview', '/special_practice_event']);"%gt;VS戸成高校%lt;/a%gt;%lt;/div%gt;
+    %lt;div class="specialBnr"%gt;%lt;a href="%lt;?= link_for('/special_practice_event') ?%gt;" onclick="javascript:_gaq.push(['_trackPageview', '/event_banner_cnt']);"%gt;VS戸成高校%lt;/a%gt;%lt;/div%gt;
 ? }
     %lt;ul class="menu"%gt;
         %lt;li%gt;%lt;a href="%lt;?= link_for('/shop') ?%gt;"%gt;購買部%lt;/a%gt;%lt;/li%gt;

本番環境へのデプロイ時にはデプロイスクリプトの最後尾で下記のスクリプトを実行するようにしてます。

#!/usr/bin/env perl

use 5.12.0;

use strict;
use warnings;
use utf8;

use FindBin::libs;

use Try::Tiny;
use LWP::UserAgent;
use Getopt::Long qw/GetOptions/;

use DateTime;
use Git::Repository;
use Path::Class qw(dir);

GetOptions(\%ARGV, qw/
  dry-run
/);

my $now  = DateTime->now(time_zone => 'Asia/Tokyo');
my $home = dir('/home/app/sites');
chdir $home;

my $history_file = $home->subdir(qw/data/)->file('deploy_history.txt');
unless (-e $history_file->stringify) {
    $history_file->touch;
}
my $deploy_history    = $history_file->slurp;
my @deploy_histories  = split /\n/, $deploy_history;

my $warning_comment   = shift @deploy_histories;
my $last_deploy       = $deploy_histories[0];

my ($date, $last_rev) = split /\s+/, $last_deploy;

my $git_repo  = Git::Repository->new(work_tree => $home);
my $rev       = $git_repo->run('log', '--pretty=format:"%h"', '-1');
$rev =~ s/\"//g;

my $diff_stat = "";
if ($last_rev) {
    $diff_stat = $git_repo->run('log', "$last_rev..$rev", "--stat");
}

if (!$ARGV{'dry-run'}) {
    say 'post np.';

    my $ua = LWP::UserAgent->new(agent => 'deployhook');
    my $np_url = 'https://xxxxx.kayac.com/np';
    my $res = $ua->post($np_url, [
        channel => '#dummy-chann',
        summary => "deploy rev $rev",
        text    => $diff_stat,
    ]);
    die $res->content unless $res->code == 302;
}
else {
    say $diff_stat;
}


if (!$ARGV{'dry-run'}) {
    say 'update deploy_history';
    my $next_history = "$now $rev";
    my $fh = $history_file->openw;
    $fh->print(join "\n", ($warning_comment, $next_history, @deploy_histories));
}


say 'done';

出力例

commit 42189e4dfff430efa9afe7e7c52a1a888d6c815e
Author: xxxxxx 
Date:   Wed Dec 12 10:35:10 2012 +0900

    change method of get link click count

 root/tmpl/default/member_top.mt |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

commit 85b8dcd18c703f156a7408dd17e23529e52189aa
Author: xxxxx 
Date:   Wed Dec 12 10:17:57 2012 +0900

    count access num of quiz link

 root/tmpl/common/footer.mt      |    2 +-
 root/tmpl/default/member_top.mt |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

最後に

gitに移行してみて感じたのは、一番大きいのはbranchの切り替えがスムーズになったことにより、 プログラマの効率ももとより、他職種とのやり取りの効率も上がったことですね。 「このbranchにあれをコミットしておいて」みたいなやり取りが以前よりも円滑できるようになりました。

苦労に対して得るものは大きかったので臆せずやるべきだったと感じてます。

とはいえSourceTreeなくしてここまでうまくいかなかっただろうなーということで、 結局一番伝えたいことはSourceTree++ってことです。

明日は若手バリスタのホープ@Keita_Shiyaのお話です。お楽しみに!