この記事ではGitの導入までに体験した苦難や失敗と、それを乗り越えた方法を紹介します。
「えっ、今更」と思われるかもしれませんが、Gitを初心者にレクチャーする際などに参考になれば幸いです。
はじめに
僕の働く開発チームは、40代〜50代の職人的なエンジニアが大半を占める、レガシーな開発環境のチームでした。開発項目と線表はExcelで管理され、バージョン管理システムは活用されておらず、何かを開発すれば何かがデグレを引き起こす、そんなことが日常茶飯事でした。
しかし今では、エンジニア全員がGitのコマンドを使えるようになり、git-flowを用いた開発やリリースを並行して進め、RedmineやGitbucketを活用しています。開発チームにGitを定着させるまでのアプローチを紹介します。
まずはGitを知ってもらう
僕はまず、Gitの特徴と使い方をまとめた資料を作り、開発チームへ説明をしました。リポジトリやステージング、リモートとローカル、ブランチ等の話を、主要なコマンドの使い方とあわせて説明したのですが、なかなかピンと来なかったようでした。
その時に受けた質問は以下の様なものでした。
- 結局svnと何が違うの?
- 同じファイルを編集したらコンフリクトするんでしょ?
- ブランチとかなんか難しそう。。。
最初の説明を聞いて「なんか難しそう」と思われてしまうと、なかなか手が出にくくなるものです。こんな工夫をしておけば、より良い説明になったと思います。
- subversionは触ったことがあるという人が多かったので、subversionとの違いやGitへ移行するメリット、svnとgitのコマンド比較があると分かりやすかった
- コマンドの紹介だけでなく、SourceTreeなどのGUIツールを用いて説明すれば、敷居が高くは感じなかったかもしれない
- git-flowを用いたブランチ運用の話はせず、メンバーがGitに慣れてからでも遅くなかった
実際にGitを使ってもらう
Gitの説明を終え、リポジトリやRedmineもバッチリ用意したところで、メンバーに定着しなければ意味がありません。「わからないことはいつでも聞いてください、駆けつけます!」と大見得を切ったのですが、まったくもって準備不足だったと思います。
ブランチの運用
ブランチの運用フローとしてgit-flowを用いていたのですが、master
, develop
ブランチはいいとして、feature
ブランチの運用方法についてキチンと定義・説明していませんでした。
結果、どんなブランチが生まれてきたかというと。。。
$ git branch --all
* master
develop
remotes/origin/feature_20151219-tanaka-temp # 田中さんが12月19日から作業を始めたブランチ
remotes/origin/feature/yamada-test # 山田さんが自分用に使っているブランチ
remotes/origin/feature/kari # 誰かがとりあえず作ったまま放置されたブランチ
そもそも、1つのコミットには1つの機能追加や修正のみを含めるとか、開発ブランチも動く状態ならばこまめにマージするとか、そういう説明を一切していなかったため、「ブランチっていうのは自分専用の作業場で、あれやこれやと機能追加をしてdevelopにマージすればいいんだ」というようなミスリードをしてしまいました。
1コミット1機能にするのは、後から必要な機能に関係するコミットだけを取り出したり、バグのあったコミットだけを打ち消したりするためである、といった理由を含めて説明しないと、正しい運用がなされるはずがありません。こまめなコミットやマージは面倒かもしれませんが、他のメンバーの開発状況も分かり、手戻りも少なくて済むといったメリットをきちんと伝えておくことが大切です。
よくある質問と対応
英語のエラーメッセージって読むのも面倒だし、何をググればいいかもよくわからない、という人っていると思います。それでも周りに質問をしてくれればサポートできるのですが、「分からないけど適当にやったらなんとかなったよ」なんて言われるとヒヤヒヤしますよね。
何人からも同じ質問を受けたので、途中からはよくあるエラーメッセージを一覧にして対処方法をまとめておくことで、他の人同士でもサポートできるようにしました。よく聞かれた質問と対策を以下で紹介しておきます。
pushできない
これは定番中の定番だと思いますが、リモートの変更内容をローカルに取り込んでいないために、push
しようとして弾かれるパターンです。「push
できなかったからpush -f
しちゃったよ」なんてことになると後が大変なので、リモートの変更を手元でmerge
/ rebase
してテストしたうえでpush
することを徹底しました。
conflictしちゃった
conflictはよくあることなのですが、困り者なのは「このファイルは自分しか編集していないはずだから、conflictしたところはすべて上書きしちゃいました」なんてことが起きること。自分の範囲に責任を持つのは素晴らしいのですが、人が良かれと思って直してくれた部分を確認もせずに消してしまっては元も子もありません。conflictした時には、git log
なりgit blame
なりをして、誰が何のために変更をしたかを確認するようにしました。
git push.defaultに関するワーニング
実はこれが一番質問を受けました。apt-get
でgitをインストールするとバージョン1.9が入るのですが、2.0からはpush時のデフォルトの挙動が変わります。そのため、git push
とブランチ名を指定せずにpushすると、configの設定をすることを推奨するワーニングが表示されます。そして、develop
やmaster
をすべてpushしようとするので、Fast-Forwardじゃないためにrejectされて、pushできないという質問が来ました。
間違いの起こりにくいgit config --global push.default simple
を設定することを推奨しています。その上でgit push origin develop
のようにpush
するブランチ名を明示的に書くように心がけています。
その他便利なコマンド
ある程度Gitに慣れてきたメンバーに教えたら「なにこれ便利じゃん」ってなったコマンドです。
git stash
git add -p
git pull --rebase
特にgit stash
とgit add -p
を知らないと、コードの一部をカットしてステージングしてコミットしてペーストしてSyntax Errorが出て、みたいなことも起きるので、効率よく作業してもらうためにも、早めに説明しておけば良かったなぁと思います。
ゴーストライター事件
これは質問ではないのですが、とてもビックリした出来事です。
開発状況を見るためにリポジトリの統計を取った時に、やたらコミットをする人と全くコミットをしない人がいることに気づきました。でもよくよく見てみると、どう考えても一人でコーディングできる量じゃないし、コミットしてない人も毎日黙々とコーディングしているし。。。まさかname
とemail
の設定が同じなのかと思ったのですが、、、そのまさかでした。
事の経緯は、最初から開発に携わっている人が開発環境の整ったVirtualBoxのマシンイメージを作成しておき、新しく開発に入った人がそのイメージをそのまま利用。みんな同一ユーザで同一のgit config
を使っていた、というものでした。
確かに環境構築は大変で開発も忙しいので、簡単に利用できる環境を提供するのは非常に正しいです。環境構築手順にGitの初期設定を追加し、マシンイメージからは.gitconfig
を削除しました。そして、push
する前にコミット内容を確認することを徹底しました。
そして運用へ
Gitを導入し、メンバーに使い方を理解してもらっても、良い運用を続けることは非常に難しいです。初めはマメにやってくれるのですがそのまま各自に任せておくと、作成されたまま放置されるチケットが増え、ブランチはマージされないまま乱立し、いずれ収集がつかなくなります。
様々な管理方法があると思いますが、僕のチームではRedmineのプロジェクトごとにメンバーを集め、チケットをベースに短時間のMTGを定期的に開くことで、極力最新の状態に保たれるようにしています。チーム全員での長時間の進捗会議とかではなく少人数の報告会形式にすることで、負担も少なく良い運用を継続できました。
さいごに
Gitの導入は始まりにしか過ぎず、テスト・デプロイの自動化やコミュニケーションツールの活用などまだまだ課題は多いです。それでも、これからGitを浸透させよう、きちんと運用されるようにしようと思っている方にとって、少しでも参考になればと幸いです。